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 ...
随机推荐
- php-fpm 重启 nginx单独配置 重启
nginx单独配置 重启 [root@ssy106c14c190c69 Api]# cd /usr/local/nginx/sbin/[root@ssy106c14c190c69 sbin]# lsn ...
- CSS之display样式
一.前言 行内标签:类似span,无法设置高度,宽度,padding,margin 块级标签:类似div,可以设置高度,宽度,padding,margin 默认情况下是这个样子的,但是可以通过disp ...
- Windows上虚拟环境的安装及使用
Why Install VirtualEnv? 可以方便的解决不同项目对类库的依赖问题. 可以在系统中Python解释器中避免包的混乱和版本的冲突. 为每个程序单独创建虚拟环境,可以保证程序只能访 ...
- python---基础知识回顾(八)数据库基础操作(sqlite和mysql)
一:sqlite操作 SQLite是一种嵌入式数据库,它的数据库就是一个文件.由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以 ...
- Writing your first academic paper
Writing your first academic paper If you are working in academics (and you are if you are working wi ...
- 你对position的了解到底有多少?
此文根据Steven Bradley的<How Well Do You Understand CSS Positioning?>所译,整个译文带有我自己的理解与思想,如果译得不好或不对之处 ...
- 8、String练习题
String练习 1.字符串反转,例如将"abc"变成"cba" 2.统计一个字符串里面另一个字符串出现的次数,例如统计"monkey" ...
- oracle07
1. 索引INDEX 1.1. 索引的概念特性和作用 概念: 简单的说,相当于一本书的目录.(数据库中的索引相当于字典的目录(索引)),它的作用就是提升查询效率. 特性: l 一种独立于表的模式(数 ...
- Strusts2笔记8--文件的上传和下载
文件的和上传和下载: (1)文件的上传: Struts是通过拦截器实现文件上传的,而默认拦截器栈中包含了文件上传拦截器,故表单通过Struts2可直接将文件上传,其底层是通过apache的common ...
- 关于注入抽象类报could not autowire field的问题
昨天工作中遇到了一个很奇葩的问题,之前一直都没考虑过抽象类这块,一直用的注入接口实现类: 先看下错误: 因为在类中注入了一个抽象类,之前只有一个继承子类,所以没问题,这里要说一下抽象类的实例化: 抽象 ...