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

界面的话就 记住选择  、按钮、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(同意页面)的更多相关文章

  1. IdentityServer4揭秘---登录

    IdentityServer4默认提供了的登录地址是Account/Index 同意页面是Consent/Index 这里我们可以通过IdentittyServer4的用户交互自定义配置设置 在Con ...

  2. IdentityServer4 禁用 Consent screen page(权限确认页面)

    IdentityServer4 在登录完成的适合,会再跳转一次页面(权限确认),如下: 我之前以为 IdentityServer4 就是这样使用的,但实际业务场景并不需要进行权限确认,而是登陆成功后直 ...

  3. asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序

    一. 概述 本篇探讨使用"基于浏览器的JavaScript客户端应用程序".与上篇实现功能一样,只不过这篇使用JavaScript作为客户端程序,而非core mvc的后台代码Ht ...

  4. asp.net core系列 57 IS4 使用混合流(OIDC+OAuth2.0)添加API访问

    一.概述 在上篇中,探讨了交互式用户身份验证,使用的是OIDC协议. 在之前篇中对API访问使用的是OAuth2.0协议.这篇把这两个部分放在一起,OpenID Connect和OAuth 2.0组合 ...

  5. IdentityServer4【Topic】之确认(Consent)

    Consent 确认 在授权请求期间,如果身份服务器需要用户同意,浏览器将被重定向到同意页面.也就是说,确认也算是IdentityServer中的一个动作.确认这个词直接翻译过来有一些古怪,既然大家都 ...

  6. IdentityServer4中文文档

    欢迎IdentityServer4 IdentityServer4是ASP.NET Core 2的OpenID Connect和OAuth 2.0框架. 它在您的应用程序中启用以下功能: 认证即服务 ...

  7. 一步一步学习IdentityServer4 (7) IdentityServer4成功配置全部配置

    auth.liyouming.com 全部配 public class Startup { public Startup(IConfiguration configuration) { Configu ...

  8. 一步一步学习IdentityServer4 (2) 开始一个简单的事例

    前面将来一些配置,但是很多都不是必要的,先放一些事例需要的简要配置把 既然是IdentityServer4 所里下面的例子我 直接放到 Linux上 测试环境 CentOS 7 +Nginx1.9.3 ...

  9. 一步一步学习IdentityServer4 (1) 概要配置说明

    //结合EFCore生成IdentityServer4数据库 // 项目工程文件最后添加 <ItemGroup><DotNetCliToolReference Include=&qu ...

随机推荐

  1. python文件加入python环境变量

    在python中,把一个python文件加入到python环境变量中,以方便其他python文件调用. 方式一: import sys sys.path.append(r'E:\syz\ly-code ...

  2. python 几种不同的格式化输出

    1. % %是最常用的格式化输出形式,后面接类型,%s,%d,%c等等 name = input() print('I am %s' % name) 2.format format也是常用格式化输出 ...

  3. maven添加docker插件无法引入,运行时报错 No plugin found for prefix 'docker'

    maven 安装不上docker插件,运行 提示:docker:bulid时No plugin found for prefix 'docker' 原因是maven不能识别 docker-maven- ...

  4. 科学计算三维可视化---Mlab基础(管线控制函数)

    科学计算三维可视化---TVTK管线与数据加载(可视化管线和图像管线了解) 科学计算三维可视化---Mayavi入门(Mayavi管线) Mlab管线控制函数的调用 Sources:数据源 Filte ...

  5. VS2010 中更改项目名称

    Time.vcxproj修改项目名称,主要是通过以下几个步骤就能完成: 修改解决方案的名称. 修改解决项目名称. 修改项目的程序集名称和默认命名空间 替换整个项目或解决方案中的出现该名称的地方. 修改 ...

  6. HDU 2176 基础NIM 输出方案

    普通的NIM,然后问先手必胜第一次操作后的所有局面. 对于一个必胜局面只要转变局面SG值为必败(SG=0)留给后手就行了. /** @Date : 2017-10-13 21:39:13 * @Fil ...

  7. 转 -- OK6410 tftp下载内核、文件系统以及nand flash地址相关整理、总结

    转载地址:http://emouse.cnblogs.com/ 飞凌官方提供了一键下载烧写linux的方式,相对来说比较方便,但是对于开发来说不够灵活,因此这篇文章把tftp相关的点介绍一下,整理下其 ...

  8. [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)

    [NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...

  9. DNS域传送漏洞

    nslookup -type=ptr 8.8.8.8             #查询一个IP地址对应的域名 nslookup -type=ns baidu.com         #查询baidu.c ...

  10. Python练习-不知道弄个什么鬼

    Alex大神,今天丢过来一个PDF,结果就成了这个样子! 1.  执行 Python 脚本的两种方式 交互方式:                   命令行 文件方式:                 ...