在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授权页的更多相关文章

  1. .NET Core IdentityServer4实战 第三章-使用EntityFramework Core进行持久化配置

    内容:本文带大家使用IdentityServer4进行使用使用EntityFramework Core进行配置和操作数据 作者:zara(张子浩) 欢迎分享,但需在文章鲜明处留下原文地址. 前两章内容 ...

  2. .NET Core IdentityServer4实战-开篇介绍与规划

    一.开篇寄语 由于假期的无聊,我决定了一个非常有挑战性的活动,也就是在年假给大家带来一个基于OAuth 2.0的身份授权框架,它就是 IdentityServer4 ,如果没有意外的话,一定可以顺利的 ...

  3. Spring实战第六章学习笔记————渲染Web视图

    Spring实战第六章学习笔记----渲染Web视图 理解视图解析 在之前所编写的控制器方法都没有直接产生浏览器所需的HTML.这些方法只是将一些数据传入到模型中然后再将模型传递给一个用来渲染的视图. ...

  4. RxJava2实战---第六章 条件操作符和布尔操作符

    RxJava2实战---第六章 条件操作符和布尔操作符 RxJava的条件操作符主要包括以下几个: amb():给定多个Observable,只让第一个发射数据的Obsrvable发射全部数据. de ...

  5. 【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 上一章,我们介绍了安装和新建控制器.视图,这一章我们来创建个数据模型,并且添加接口和实现类. 添加EF上下文对象 按照我们以前 ...

  6. 2017.2.28 activiti实战--第六章--任务表单(二)外置表单

    学习资料:<Activiti实战> 第六章 任务表单(二)外置表单 6.3 外置表单 考虑到动态表单的缺点(见上节),外置表单使用的更多. 外置表单的特点: 页面的原样显示 字段值的自动填 ...

  7. 2017.2.28 activiti实战--第六章--任务表单(一)动态表单

    学习资料:<Activiti实战> 第六章 任务表单(一)动态表单 内容概览:本章要完成一个OA(协同办公系统)的请假流程的设计,从实用的角度,讲解如何将activiti与业务紧密相连. ...

  8. 2017.2.22 activiti实战--第六章--任务表单

    学习资料:<Activiti实战> 第六章 任务表单 本章将一步步完成一个协同办公系统(OA)的请假流程的设计,讲解如何将Activiti和实际业务联系起来. 首先讲解动态表单与外置表单的 ...

  9. 【无私分享:ASP.NET CORE 项目实战(第九章)】创建区域Areas,添加TagHelper

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在Asp.net Core VS2015中,我们发现还有很多不太简便的地方,比如右击添加视图,转到试图页等功能图不见了,虽然我 ...

随机推荐

  1. 【树转数组】poj1195

    /* 二维的树状数组: 更新某个元素时: NO.1:c[n1],c[n2],c[n3],....,c[nm]; 当中n1 = i,n(i+1) = ni+lowbit(ni); nm+lowbit(n ...

  2. krpano全球漫游相同的声音和声音添加的场景(文章内容已移至krpano中国网站)

    请关注微信订阅号 krpano   watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG1ob2s=/font/5a6L5L2T/fontsize/400/f ...

  3. QuickReport的OnNeedData的触发情况

    1.设置QuickReport的DataSet为空.2.在QuickReport的BeforePrint里面将要显示的数据集合初始化,如Query1.First;3.在OnNeedData里面写代码, ...

  4. 协程在Web服务器中的应用(配的图还不错)

    协程(纤程,微线程)这个概念早就有之,各家互联网公司也都有研究,但在国内各大论坛和大会热起来,还是今年的事. 最近参与讨论开放平台建设和架构设计过程中,有同事提到了使用协程代替线程,能够很大幅度的提高 ...

  5. SQL SERVER LEAD和LAG使用

    示例:获取在48小时之内重复的记录 SELECT * FROM ( SELECT b.* , LAG(b.OperatorTime, , b.OperatorTime) OVER ( PARTITIO ...

  6. 那些证书相关的玩意儿(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12等)(使用OpenSSL的命令行)

    之前没接触过证书加密的话,对证书相关的这些概念真是感觉挺棘手的,因为一下子来了一大堆新名词,看起来像是另一个领域的东西,而不是我们所熟悉的编程领域的那些东西,起码我个人感觉如此,且很长时间都没怎么搞懂 ...

  7. 动态lambda 构建

    var param = Expression.Parameter(typeof(T)); var datetime1 = Expression.Constant(dt1); var datetime2 ...

  8. Z-Order

    The z-order of a window indicates the window's position in a stack of overlapping windows. This wind ...

  9. Qt 事件处理 快捷键(重写eventFilter的函数,使用Qt::ControlModifier判断)

    CTRL+Enter发送信息的实现 在现在的即时聊天程序中,一般都设置有快捷键来实现一些常用的功能,类似QQ可以用CTRL+Enter来实现信息的发送. 在QT4中,所有的事件都继承与QEvent这个 ...

  10. 零元学Expression Blend 4 - Chapter 42 五分钟快速完成扇形变圆形动画

    原文:零元学Expression Blend 4 - Chapter 42 五分钟快速完成扇形变圆形动画 零元学Expression Blend 4 - Chapter 42 五分钟快速完成扇形变圆形 ...