IdentityServer4揭秘---Consent(同意页面)
授权同意页面与登录一样首先要分析页面的需要什么模型元素后建立相关的模型类

界面的话就 记住选择 、按钮、RuturnUrl、以及选择的资源Scope
/// <summary>
/// 主要绑定Consent界面上的一些模型
/// </summary>
public class ConsentViewModel
{
public string ReturnUrl { get; set; }
public bool RememberConsent { get; set; }
public string Button { get; set; }
public IEnumerable<string> ScopesConsented { get; set; }
}
ConsentViewModel
这里可以注意到还有Idr4的对应数据 比如客户端的一些信息,如名称、Logo、客户端的授权Scope等等、这里根据需要可以多写一些
/// <summary>
/// 主要绑定Idr4中关于Consent界面交互的实体字段
/// </summary>
public class Idr4ConsentViewModel : ConsentViewModel
{
public string ClientName { get; set; }
public string ClientUrl { get; set; } public string ClientLogoUrl { get; set; } public bool AllowRememberConsent { get; set; } public IEnumerable<Idr4ScopeViewModel> IdentityScopes { get; set; }
public IEnumerable<Idr4ScopeViewModel> ResouceScopes { get; set; }
}
Idr4ConsentViewModel
这里同样需要构建Idr4Consent页面展示模型
private async Task<Idr4ConsentViewModel> CreateIdr4ConsentViewModelAsync(string ReturnUrl)
{
var request = await _identityServerInteractionService.GetAuthorizationContextAsync(ReturnUrl);
if (request != null)
{
//通过客户端id获取客户端信息
var clientModel = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
if (clientModel != null)
{
//获取资源Scope信息 这里包括了两种 一种是IdentityResource 和ApiResource var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
//获取所有的权限 // var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(clientModel.AllowedScopes); if (resources != null && (resources.ApiResources.Any() || resources.IdentityResources.Any()))
{
//构造界面需要的模型 var vm = new Idr4ConsentViewModel(); //界面初始化时候
vm.RememberConsent = true; //默认true
vm.ScopesConsented = Enumerable.Empty<string>();
vm.ReturnUrl = ReturnUrl;
//构建关于Client的信息
vm.ClientName = clientModel.ClientName;
vm.ClientUrl = clientModel.ClientUri;
vm.ClientLogoUrl = clientModel.LogoUri;
vm.AllowRememberConsent = clientModel.AllowRememberConsent;
vm.IdentityScopes = resources.IdentityResources.Select(x => new Idr4ScopeViewModel
{
Name = x.Name,
DisplayName = x.DisplayName,
Description = x.Description,
Emphasize = x.Emphasize,
Required = x.Required,
Checked = vm.ScopesConsented.Contains(x.Name) || x.Required
}).ToArray();
vm.ResouceScopes = resources.ApiResources.SelectMany(x => x.Scopes).Select(k => new Idr4ScopeViewModel
{
Name = k.Name,
DisplayName = k.DisplayName,
Description = k.Description,
Emphasize = k.Emphasize,
Required = k.Required,
Checked = vm.ScopesConsented.Contains(k.Name) || k.Required }).ToArray();
//离线
if (ConsentOptions.EnableOfflineAccess && resources.OfflineAccess)
{
vm.ResouceScopes = vm.ResouceScopes.Union(new Idr4ScopeViewModel[] {
new Idr4ScopeViewModel{ Name = IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess,
DisplayName = ConsentOptions.OfflineAccessDisplayName,
Description = ConsentOptions.OfflineAccessDescription,
Emphasize = true,
Checked = vm.ScopesConsented.Contains(IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess)
}
});
}
return vm;
}
else
{
//客户端Scope不存在 可以在界面提示并记录日志
return null;
} }
else
{
//客户端不存在 可以在界面提示并记录日志
return null; } }
return null;
}
CreateIdr4ConsentViewModelAsync
里面具体的话无非就是获取更具ReturnUrl地址获取用户交互接口相关的数据信息以及页面Scope绑定以及获取
值得注意的 选项required这种情况在界面上是 disabled属性 后台Action中是获取不到的,所以需要加一些影藏域
这里是Get Consent
[HttpGet]
public async Task<IActionResult> Consent(string ReturnUrl)
{
//获取请求授权信息
var vm = await CreateIdr4ConsentViewModelAsync(ReturnUrl);
if (vm != null)
{
return View(vm);
}
return View();
}
Consent Get
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Consent(Idr4ConsentViewModel model)
{ ConsentResponse consentResponse = null; if (model == null)
{
ModelState.AddModelError("", "数据发送异常");
}
//有没有选择授权 if (model.ScopesConsented == null || model.ScopesConsented.Count() == )
{
ModelState.AddModelError("", "请至少选择一个权限");
} //同意授权
if (model.Button == "yes")
{
//选择了授权Scope
if (model.ScopesConsented != null && model.ScopesConsented.Any())
{
var scopes = model.ScopesConsented;
if (ConsentOptions.EnableOfflineAccess == false)
{
scopes = scopes.Where(x => x != IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess);
} consentResponse = new ConsentResponse
{
RememberConsent = model.RememberConsent,
ScopesConsented = scopes
}; }
}
//不同意授权
else if (model.Button == "no")
{
consentResponse = ConsentResponse.Denied;
}
else
{
var vm1 = await CreateIdr4ConsentViewModelAsync(model.ReturnUrl);
return View(vm1); } //无论同意还是不同意都是需要跳转
if (consentResponse != null)
{ var request = await _identityServerInteractionService.GetAuthorizationContextAsync(model.ReturnUrl);
if (request == null)
{
ModelState.AddModelError("", "客户端登录验证不匹配");
}
//if (consentResponse == ConsentResponse.Denied)
//{
// string url = new Uri(request.RedirectUri).Authority;
// return Redirect(url);
//} //沟通Idr4服务端实现授权
await _identityServerInteractionService.GrantConsentAsync(request, consentResponse); return Redirect(model.ReturnUrl); } var vm = await CreateIdr4ConsentViewModelAsync(model.ReturnUrl);
if (vm != null)
{
return View(vm);
} return View();
}
Consent Post
@using SSOServer.Models;
@model Idr4ConsentViewModel
@{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<meta name="viewport" content="width=device-width" />
<title>确认授权页面</title>
</head>
<body>
<div>
<div><img src="@Model.ClientLogoUrl" width="" height="" /></div>
<div>@Model.ClientName</div>
<div><a href="@Model.ClientUrl" target="_blank"> @Model.ClientUrl</a></div>
</div>
<div>
<div asp-validation-summary="All"></div>
<form asp-action="Consent" class="consent-form">
<input type="hidden" asp-for="ReturnUrl" />
<div>请求你的授权</div> @if (Model.IdentityScopes.Any())
{
<div class="panel panel-default consent-buttons">
<div class="panel-heading">
<span class="glyphicon glyphicon-user"></span>
个人信息
</div>
<ul class="list-group">
@foreach (var scope in Model.IdentityScopes)
{
<li class="list-group-item">
<label>
<input class="consent-scopecheck"
type="checkbox"
name="ScopesConsented"
id="scopes_@scope.Name"
value="@scope.Name"
checked="@scope.Checked"
disabled="@scope.Required" />
@if (scope.Required)
{
<input type="hidden"
name="ScopesConsented"
value="@scope.Name" />
}
<strong>@scope.DisplayName</strong>
@if (scope.Emphasize)
{
<span class="glyphicon glyphicon-exclamation-sign"></span>
}
</label>
@if (scope.Required)
{
<span><em>(必需)</em></span>
}
@if (scope.Description != null)
{
<div class="consent-description">
<label for="scopes_@scope.Name">@scope.Description</label>
</div>
}
</li>
}
</ul>
</div>
}
@if (Model.ResouceScopes.Any())
{
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-tasks"></span>
应用授权
</div>
<ul class="list-group">
@foreach (var scope in Model.ResouceScopes)
{
<li class="list-group-item">
<label>
<input class="consent-scopecheck"
type="checkbox"
name="ScopesConsented"
id="scopes_@scope.Name"
value="@scope.Name"
checked="@scope.Checked"
disabled="@scope.Required" />
@if (scope.Required)
{
<input type="hidden"
name="ScopesConsented"
value="@scope.Name" />
}
<strong>@scope.DisplayName</strong>
@if (scope.Emphasize)
{
<span class="glyphicon glyphicon-exclamation-sign"></span>
}
</label>
@if (scope.Required)
{
<span><em>(必需)</em></span>
}
@if (scope.Description != null)
{
<div class="consent-description">
<label for="scopes_@scope.Name">@scope.Description</label>
</div>
}
</li>
}
</ul>
</div>
}
@if (Model.AllowRememberConsent)
{
<div class="consent-remember">
<label>
<input class="consent-scopecheck" asp-for="RememberConsent" />
<strong>记住选择</strong>
</label>
</div>
}
<div class="consent-buttons">
<button name="button" value="yes" class="btn btn-primary" autofocus>是, 允许</button>
<button name="button" value="no" class="btn">否,不允许</button> </div>
</form> </div> </body>
</html>
Consent View
IdentityServer4揭秘---Consent(同意页面)的更多相关文章
- IdentityServer4揭秘---登录
IdentityServer4默认提供了的登录地址是Account/Index 同意页面是Consent/Index 这里我们可以通过IdentittyServer4的用户交互自定义配置设置 在Con ...
- IdentityServer4 禁用 Consent screen page(权限确认页面)
IdentityServer4 在登录完成的适合,会再跳转一次页面(权限确认),如下: 我之前以为 IdentityServer4 就是这样使用的,但实际业务场景并不需要进行权限确认,而是登陆成功后直 ...
- asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序
一. 概述 本篇探讨使用"基于浏览器的JavaScript客户端应用程序".与上篇实现功能一样,只不过这篇使用JavaScript作为客户端程序,而非core mvc的后台代码Ht ...
- asp.net core系列 57 IS4 使用混合流(OIDC+OAuth2.0)添加API访问
一.概述 在上篇中,探讨了交互式用户身份验证,使用的是OIDC协议. 在之前篇中对API访问使用的是OAuth2.0协议.这篇把这两个部分放在一起,OpenID Connect和OAuth 2.0组合 ...
- IdentityServer4【Topic】之确认(Consent)
Consent 确认 在授权请求期间,如果身份服务器需要用户同意,浏览器将被重定向到同意页面.也就是说,确认也算是IdentityServer中的一个动作.确认这个词直接翻译过来有一些古怪,既然大家都 ...
- IdentityServer4中文文档
欢迎IdentityServer4 IdentityServer4是ASP.NET Core 2的OpenID Connect和OAuth 2.0框架. 它在您的应用程序中启用以下功能: 认证即服务 ...
- 一步一步学习IdentityServer4 (7) IdentityServer4成功配置全部配置
auth.liyouming.com 全部配 public class Startup { public Startup(IConfiguration configuration) { Configu ...
- 一步一步学习IdentityServer4 (2) 开始一个简单的事例
前面将来一些配置,但是很多都不是必要的,先放一些事例需要的简要配置把 既然是IdentityServer4 所里下面的例子我 直接放到 Linux上 测试环境 CentOS 7 +Nginx1.9.3 ...
- 一步一步学习IdentityServer4 (1) 概要配置说明
//结合EFCore生成IdentityServer4数据库 // 项目工程文件最后添加 <ItemGroup><DotNetCliToolReference Include=&qu ...
随机推荐
- cuckoo 安装
最新 https://www.jianshu.com/p/f623fa0bebf9 http://www.freebuf.com/articles/system/123816.html http:// ...
- mysql数据库脚本改为oracle脚本
前段时间公司项目数据库需要从mysql转为oracle,所以需要修改下原有的mysql脚本. 有两种方式:第一种,使用工具进行两种数据库的转换.第二种,手动修改数据库脚本. 第二种方法很笨,但能学习下 ...
- bzoj千题计划116:bzoj1025: [SCOI2009]游戏
http://www.lydsy.com/JudgeOnline/problem.php?id=1025 题目转化: 将n分为任意段,设每段的长度分别为x1,x2,…… 求lcm(xi)的个数 有一个 ...
- [HTML5和Flash视频播放器]Video.js 学习笔记(一 ) HLS库:videojs-contrib-hls
DEMO地址:https://github.com/Tinywan/PHP_Experience https://github.com/videojs/videojs-contrib-hls 下载JS ...
- Training Neural Networks: Q&A with Ian Goodfellow, Google
Training Neural Networks: Q&A with Ian Goodfellow, Google Neural networks require considerable t ...
- JavaScript 延时与定时
一.定时(setInterval) var i = 0; function hello(){ console.log(i++); } setInterval(hello,1000); // 每一秒执行 ...
- Java并发编程原理与实战三十七:线程池的原理与使用
一.简介 线程池在我们的高并发环境下,实际应用是非常多的!!适用频率非常高! 有过使用过Executors框架的朋友,可能不太知道底层的实现,这里就是讲Executors是由ThreadPoolExe ...
- TPL概要
ReaderWriterLockSlim.读写锁,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁.只有等到对象被写入锁占用的时候,才会阻塞 Barrier .它允许 ...
- UNIX网络编程 第1章:简介和TCP/IP
1.1 按1.9节未尾的步骤找出你自己的网络拓扑的信息. 1.2 获取本书示例的源代码(见前言),编译并测试图1-5所示的TCP时间获取客户程序.运行这个程序若干次,每次以不同IP地址作为命令行参数. ...
- Dream------scala--开发环境搭建
scala简介: scala是一门函数式编程和面向对象编程结合的语言 函数式编程非常擅长数值计算而面向对象特别适合于大型工程或项目的组织以及团队的分工合作 我们借助scala可以非常优雅的构造出各种规 ...