.NET Core IdentityServer4实战 第六章-Consent授权页
在identityServer4中登陆页面只要是成功了,就会注册一个Cookie在服务器资源上,像现在大部分的网站第三方授权,都是经过一个页面,然后选需要的功能,IdentityServer4也给我们提供了,只要你登陆成功,就会跳转到Consent/Index(Get)中,所以我们只要在其中做手脚就好了。
在编写代码之前我们要知道IdentityServer的三个接口, IClientStore 是存放客户端信息的, IResourceStore 是存放资源API信息的,这两个接口都是在IdentityServer4的Stores的命名空间下,还有一个接口是 IIdentityServerInteractionService 用于与IdentityServer通信的服务,主要涉及用户交互。它可以从依赖注入系统获得,通常作为构造函数参数注入到IdentityServer的用户界面的MVC控制器中。
下面我们创建一个Consent控制器在认证服务器上,名为 ConsentController ,在其中我们需要将这三个接口通过构造函数构造进来。
public class ConsentController : Controller
{
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
private readonly IIdentityServerInteractionService _identityServerInteractionService;
public ConsentController(
IClientStore clientStore,
IResourceStore resourceStore,
IIdentityServerInteractionService identityServerInteractionService)
{
_clientStore = clientStore;
_resourceStore = resourceStore;
_identityServerInteractionService = identityServerInteractionService;
}
}
在控制器中,因为登陆成功是从Account控制器调过来的,那个时候还带着ReturnUrl这个而参数,我们在这个控制器中也需要ReturnUrl,所以在Get方法中写上该参数,要不然跳转不过来的。
public async Task<IActionResult> Index(string returnUrl)
{
var model =await BuildConsentViewModel(returnUrl);return View(model);
}
其中调用了 BuildConsentViewModel 方法用于返回一个consent对象,其中我们使用 _identityServerInteractionService 接口获取了上下文,然后再通过其余的两个接口找到它客户端还有资源api的信息。然后再调用了自定义的 CreateConsentViewModel 对象创建了consent对象。
/// <summary>
/// 返回一个consent对象
/// </summary>
private async Task<ConsentVm> BuildConsentViewModel(string returlUrl)
{
//获取验证上下文
var request = await _identityServerInteractionService.GetAuthorizationContextAsync(returlUrl);
if (request == null)
return null;
//根据上下文获取client的信息以及资源Api的信息
var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
//创建consent对象
var vm = CreateConsentViewModel(request,client,resources);
vm.ReturnUrl = returlUrl;
return vm;
}
在其中创建对象并返回,只不过在获取ResourceScopes的时候,它是一个ApiResource,所以需要先转换成Scopes然呢再Select一下变成我们的ViewModel.
/// <summary>
/// 创建consent对象
/// </summary>
private ConsentVm CreateConsentViewModel(AuthorizationRequest request,Client client,Resources resources)
{
var vm = new ConsentVm();
vm.ClientId = client.ClientId;
vm.Logo = client.LogoUri;
vm.ClientName = client.ClientName;
vm.ClientUrl = client.ClientUri;//客户端url
vm.RemeberConsent = client.AllowRememberConsent;//是否记住信息
vm.IdentityScopes = resources.IdentityResources.Select(i=>CreateScopeViewModel(i));
vm.ResourceScopes = resources.ApiResources.SelectMany(u => u.Scopes).Select(x => CreatesScoreViewModel(x));
return vm;
}
public ScopeVm CreatesScoreViewModel(Scope scope)
{
return new ScopeVm
{
name = scope.Name,
DisplayName = scope.DisplayName,
Description = scope.Description,
Required = scope.Required,
Checked = scope.Required,
Emphasize = scope.Emphasize
};
}
private ScopeVm CreateScopeViewModel(IdentityResource identityResource)
{
return new ScopeVm
{
name = identityResource.Name,
DisplayName = identityResource.DisplayName,
Description = identityResource.Description,
Required = identityResource.Required,
Checked = identityResource.Required,
Emphasize = identityResource.Emphasize
};
}
以上我们的控制器就完成了,现在我们搞一下视图,在视图中我们就是简单做一下,使用ConsentVm作为视图绑定对象,在之中我遇到了一个Bug,我用 @Html.Partial("_ScopeListItem", item); 的时候突然就报错了,在页面上显示一个Task一大堆的错误信息,我也不知道啥情况(望大佬解决),换成不是异步的就行了。
<p>Consent Page</p>
@using mvcWebFirstSolucation.Models;
@model ConsentVm
<div class="row page-header">
<div class="col-sm-10">
@if (!string.IsNullOrWhiteSpace(Model.Logo))
{
<div>
<img src="@Model.Logo" />
</div>
}
<h1>
@Model.ClientName
<small>欢迎来到第三方授权</small>
</h1> </div>
</div>
<div class="row">
<div class="col-sm-8">
<form asp-action="Index">
<input type="hidden" asp-for="ReturnUrl" />
<div class="panel">
<div class="panel-heading">
<span class="glyphicon glyphicon-tasks"></span>
用户信息
</div>
<ul class="list-group">
@foreach (var item in Model.IdentityScopes)
{
@Html.Partial("_ScopeListItem", item);
}
</ul>
</div>
<div class="panel">
<div class="panel-heading">
<span class="glyphicon glyphicon-tasks"></span>
应用权限
</div>
<ul class="list-group">
@foreach (var item in Model.ResourceScopes)
{
@Html.Partial("_ScopeListItem", item);
}
</ul>
</div> <div>
<label>
<input type="checkbox" asp-for="RemeberConsent" />
<strong>记住我的选择</strong>
</label>
</div>
<div>
<button value="yes" class="btn btn-primary" name="button" autofocus>同意</button>
<button value="no" name="button">取消</button>
@if (!string.IsNullOrEmpty(Model.ClientUrl))
{
<a href="@Model.ClientUrl" class="pull-right btn btn-default">
<span class="glyphicon glyphicon-info-sign"></span>
<strong>@Model.ClientUrl</strong>
</a>
}
</div>
</form>
</div>
</div>
下面是局部视图的定义,传过来的对象是 ResourceScopes 和 IdentityScopes ,但他们都是对应ScopeVm,在其中呢就是把他们哪些权限列出来,然后勾选,在它的父页面已经做了post提交,所以我们还得弄个控制器。
@using mvcWebFirstSolucation.Models;
@model ScopeVm <li>
<label>
<input type="checkbox"
name="ScopesConsented"
id="scopes_@Model.name"
value="@Model.name"
checked="@Model.Checked"
disabled="@Model.Required"/> @if (Model.Required)
{
<input type="hidden" name="ScopesConsented" value="@Model.name" />
} <strong>@Model.name</strong>
@if (Model.Emphasize)
{
<span class="glyphicon glyphicon-exclamation-sign"></span>
}
</label>
@if (!string.IsNullOrEmpty(Model.Description))
{
<div>
<label for="scopes_@Model.name">@Model.Description</label>
</div>
}
</li>
这个方法的参数是我们所自定义的实体,其中有按钮还有返回的地址,在其中我们判断了是否选择OK,选择不那就直接赋一个拒绝的指令,如果ok那么就直接判断是否有这个权力,因为我们在config中进行了配置,然后如果有,呢么就直接添加,在不==null的清空下,我们根据 returlUrl 这个字符串获取了请求信息,然后通过 GrantConsentAsync 方法直接同意了授权,然后直接跳转过去,就成功了。
[HttpPost]
public async Task<IActionResult> Index(InputConsentViewModel viewmodel)
{
// viewmodel.ReturlUrl
ConsentResponse consentResponse = null;
if (viewmodel.Button =="no")
{
consentResponse = ConsentResponse.Denied;
}
else
{
if (viewmodel.ScopesConsented !=null && viewmodel.ScopesConsented.Any())
{
consentResponse = new ConsentResponse
{
RememberConsent = viewmodel.RemeberConsent,
ScopesConsented = viewmodel.ScopesConsented
};
}
}
if (consentResponse != null)
{
var request = await _identityServerInteractionService.GetAuthorizationContextAsync(viewmodel.ReturnUrl);
await _identityServerInteractionService.GrantConsentAsync(request, consentResponse);
return Redirect(viewmodel.ReturnUrl);
}
return View(await BuildConsentViewModel(viewmodel.ReturnUrl));
}
最后,在调试的时候一定要Client的 RequireConsent 设置为true.
.NET Core IdentityServer4实战 第六章-Consent授权页的更多相关文章
- .NET Core IdentityServer4实战 第三章-使用EntityFramework Core进行持久化配置
内容:本文带大家使用IdentityServer4进行使用使用EntityFramework Core进行配置和操作数据 作者:zara(张子浩) 欢迎分享,但需在文章鲜明处留下原文地址. 前两章内容 ...
- .NET Core IdentityServer4实战-开篇介绍与规划
一.开篇寄语 由于假期的无聊,我决定了一个非常有挑战性的活动,也就是在年假给大家带来一个基于OAuth 2.0的身份授权框架,它就是 IdentityServer4 ,如果没有意外的话,一定可以顺利的 ...
- Spring实战第六章学习笔记————渲染Web视图
Spring实战第六章学习笔记----渲染Web视图 理解视图解析 在之前所编写的控制器方法都没有直接产生浏览器所需的HTML.这些方法只是将一些数据传入到模型中然后再将模型传递给一个用来渲染的视图. ...
- RxJava2实战---第六章 条件操作符和布尔操作符
RxJava2实战---第六章 条件操作符和布尔操作符 RxJava的条件操作符主要包括以下几个: amb():给定多个Observable,只让第一个发射数据的Obsrvable发射全部数据. de ...
- 【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 上一章,我们介绍了安装和新建控制器.视图,这一章我们来创建个数据模型,并且添加接口和实现类. 添加EF上下文对象 按照我们以前 ...
- 2017.2.28 activiti实战--第六章--任务表单(二)外置表单
学习资料:<Activiti实战> 第六章 任务表单(二)外置表单 6.3 外置表单 考虑到动态表单的缺点(见上节),外置表单使用的更多. 外置表单的特点: 页面的原样显示 字段值的自动填 ...
- 2017.2.28 activiti实战--第六章--任务表单(一)动态表单
学习资料:<Activiti实战> 第六章 任务表单(一)动态表单 内容概览:本章要完成一个OA(协同办公系统)的请假流程的设计,从实用的角度,讲解如何将activiti与业务紧密相连. ...
- 2017.2.22 activiti实战--第六章--任务表单
学习资料:<Activiti实战> 第六章 任务表单 本章将一步步完成一个协同办公系统(OA)的请假流程的设计,讲解如何将Activiti和实际业务联系起来. 首先讲解动态表单与外置表单的 ...
- 【无私分享:ASP.NET CORE 项目实战(第九章)】创建区域Areas,添加TagHelper
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在Asp.net Core VS2015中,我们发现还有很多不太简便的地方,比如右击添加视图,转到试图页等功能图不见了,虽然我 ...
随机推荐
- 【树转数组】poj1195
/* 二维的树状数组: 更新某个元素时: NO.1:c[n1],c[n2],c[n3],....,c[nm]; 当中n1 = i,n(i+1) = ni+lowbit(ni); nm+lowbit(n ...
- 代码首要的目标应该是“解决问题”(包括“没有 bug”),其次的目标才是“简单优雅”。
什么是现实理想主义者 曾经有人看了我的文章,以为我是一个“理想主义者”,来找我聊天.他说:“你知道吗,我跟你一样喜欢简单优雅的代码.上次我在某公司工作,看到他们的代码乱得不成样子,二话没说给他们重写了 ...
- python 教程 第十四章、 地址薄作业
第十四章. 地址薄作业 #A Byte of Python #!/usr/bin/env python import cPickle import os #define the contacts fi ...
- JQUERY名称冲突
jQuery 使用 $ 作为符号 jQuery 介绍的简单方法. 其他 JavaScript 库函数(例 Prototype)使用相同的 $ 符号. jQuery 使用命名 noConflict() ...
- 照片美妆---基于Haar特征的Adaboost级联人脸检测分类器
原文:照片美妆---基于Haar特征的Adaboost级联人脸检测分类器 本文转载自张雨石http://blog.csdn.net/stdcoutzyx/article/details/3484223 ...
- ubuntu Linux 操作系统安装与配置
Ubuntu是一个以桌面应用为主的Linux操作系统.Ubuntu每六个月发布一个新版本(一般是4和10月份,命名为YY.MM),每一个普通版本都将被支持 18个月,长期支持版(Long Term S ...
- eclipse 插件编写(一)
由于项目开发进程中有一些重复性的代码进行编写,没有任何业务逻辑,粘贴复制又很麻烦且容易出错,故想起做一个eclipse插件来满足一下自己的工作需要,同时记录一下,以供以后参考与共同学习.本文主要讲解一 ...
- 利用Socket通信
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 建立网络通信连接至少要一对端口号(socket).socket本质是编程接口(API),对TCP/IP的封装 ...
- Delphi皮肤之 - 图片按钮
效果如图,支持普通.移上去.按下.弹起.禁用5种状态. unit BmpBtn; interface uses Windows, Messages, SysUtils, Classes, Graphi ...
- OAUTH2 SAML2.0
OAuth2 - http://www.cnblogs.com/linianhui/p/oauth2-authorization.html SAML - wikipedia Shibboleth / ...