IdentityServer4客户端如何获取自定义声明,了解一下?
前言
久违了各位,之前录制过IdentityServer4的基础视频(https://space.bilibili.com/319652230/#/),有兴趣了解的童鞋可以看一下,只不过未发表成博客。我们使用IdentityServer4结和ASP.NET Identity来进行用户的认证和授权管理,在实际项目中我们都会继承ASP.NET Core Identity中IdentityUser类即用户实体,并添加我们自定义的扩展属性,在客户端(Clients)中我们只能拿到用户Id,但是若我们要获取用户中其他重要的属性,此时相对于IdentityServer4而言则需要自定义声明,那么在IdentityServer4中如何添加自定义声明并在客户端中能正确获取到呢?本文详细讲解一下,对于IdentityServer4我也是初学者,仅仅止于知道和使用而已,若有错误的地方,还请大佬指正。
IdentityServer4添加自定义声明(方式一)
首先我们继承自IdentityUser类并添加额外的属性比如部门Id,如下:
public class OnLineBookIdentityUser : IdentityUser
{
public string DepartmentId { get; set; }
}
接下来我们需要将部门Id通过IdentityServer4添加到声明中,在IdentityServer4中添加自定义声明我们需要实现IProfileService接口,该接口有如下两个方法。
我们实现上述两个方法,在第一个方法中参数也就是用户基本信息上下文中拿到用户Id即Subject,然后我们定义用户中的部门Id属性为idr,并将用户中的部门Id属性映射到声明的idr中,最终实现如下:
public class ProfileService : IProfileService
{
protected UserManager<OnLineBookIdentityUser> _userManager; public ProfileService(UserManager<OnLineBookIdentityUser> userManager)
{
_userManager = userManager;
} public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = _userManager.GetUserAsync(context.Subject).Result; var claims = new List<Claim>
{
new Claim("idr", user.DepartmentId),
}; context.IssuedClaims.AddRange(claims);
return Task.FromResult();
} public Task IsActiveAsync(IsActiveContext context)
{
var user = _userManager.GetUserAsync(context.Subject).Result;
context.IsActive = true;
return Task.FromResult();
}
}
接下来在注入IdentityServer4时,添加我们自定义实现的ProfileService,更多基础请参考IdentityServer4官网以及我所录制的IdentityServer4基础视频。
//注入IdentityServer4使用AspNetIdentity
services.AddIdentityServer(options =>
{
options.Authentication.CookieLifetime = TimeSpan.FromMinutes();
})
.AddDeveloperSigningCredential()
.AddAspNetIdentity<OnLineBookIdentityUser>()
....
.AddProfileService<ProfileService>();
晓晨姐姐在他发表的博客文章(http://www.cnblogs.com/stulzq/p/8726002.html)中说必须还要实现IResourceOwnerPasswordValidator接口,那么在客户端获取到自定义声明应该是通过调用接口的方式获取用户自定义声明(不知是否理解正确或者说通过客户端中User中Principal获取到呢?)这里我们并未实现上述IResourceOwnerPasswordValidator接口,我们看看在客户端是否能拿到上述我们声明的idr呢?在客户端我们定义如下控制器,访问需要进行授权,并获取我们添加的自定义声明idr,如下:
[Route("[controller]"), Authorize]
public class OrderController : Controller
{
private readonly IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
} [HttpGet("index")]
public IActionResult Index()
{
var idr = User.FindFirst("idr")?.Value;
return View(nameof(Index), idr);
}
}
并在上述index视图中我们答应自定义声明idr所对应的部门的值,如下:
@model string
@if (Model is null)
{ <h1>idr is null</h1>
}
else
{
<h1>@Model.ToString()</h1>
}
接下来我们通过动态gif来演示下,注意如下视频http://localhost:5000/为IdentityServer4认证、授权服务器端。而http://localhost:5003/为客户端。
上述我们可以看到在登录之后重定向到客户端,我们拿到ack即AccessToken里面有自定义声明idr,但是当我们访问Order/Index并未获取到idr,这是为何,这是因为我们通过如下即ClaimPrincipal去获取idr时,实际上是获取的id_token里面的用户信息,而不是AccessToken,而id_token我们看到没有idr,所以才出现没有获取到的情况。
var idr = User.FindFirst("idr")?.Value;
为了解决这个问题,我们可以在通过IdentityServer4创建的Clients表中所对应的调用客户端中的如下列设置为True即可。
接下来我们再来演示一下,此时我们将看到解析通过id_token将返回idr,并能在客户端读取到idr。
IdentityServer4添加自定义声明(方式二)
除了上述方式通过实现ProfileService接口外,我们还可以通过实现自定义UserClaimsPrincipalFactory工厂类来实现,复写CreateAsync方法来创建自定义声明如下:
public class CustomizeUserClaimsFactory<TRole> : UserClaimsPrincipalFactory<OnLineBookIdentityUser, TRole>
where TRole : class
{
public CustomizeUserClaimsFactory(UserManager<OnLineBookIdentityUser> userManager, RoleManager<TRole> roleManager, IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{
} public async override Task<ClaimsPrincipal> CreateAsync(OnLineBookIdentityUser user)
{
var cliamsPrincipal = await base.CreateAsync(user);
var identity = cliamsPrincipal.Identities.First(); if (!identity.HasClaim(x => x.Type == "idr"))
{
identity.AddClaim(new Claim("idr", user.DepartmentId));
} return cliamsPrincipal;
}
}
然后通过创建扩展方法将上述自定义用户声明工厂进行注入,如下:
public static IdentityBuilder AddCustomizeUserClaimsPrincipalFactory(this IdentityBuilder builder)
{
var interfaceType = typeof(IUserClaimsPrincipalFactory<>);
interfaceType = interfaceType.MakeGenericType(builder.UserType); var classType = typeof(CustomizeUserClaimsFactory<>);
classType = classType.MakeGenericType(builder.RoleType); builder.Services.AddScoped(interfaceType, classType); return builder;
}
最后在注入Identity时,添加上述自定义声明工厂,如下:
services.AddIdentity<OnLineBookIdentityUser, IdentityRole>()
.AddEntityFrameworkStores<OnLineBookDbContext>()
.AddDefaultTokenProviders()
.AddCustomizeUserClaimsPrincipalFactory();
总结
本节内容需要有一定IdentityServer4基础,如若不太了解请参考官方文档,同时针对如上在客户端如何获取自定义声明,重点在于在对应客户端表中设置AlwaysIncludeInIdToken为True才好使,并未去深究设置该列为True所产生的副作用,感谢阅读,若有不同见解,望留下您的评论。
IdentityServer4客户端如何获取自定义声明,了解一下?的更多相关文章
- [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文
我们在asp.net 开发中已经封装了最强大的HttpContext,我们可以在HttpContext中可以获取到几乎任何想获取的东西,也可以在HttpContext写入需要返回客户端的信息.但是这些 ...
- AOP中获取自定义注解的参数值
目录 一.利用注解实现AOP的基本流程 1.1.创建一个注解,用来注解切点(pointcut) 1.2.创建一个service,使用上面定义的注解来指定切点 1.3.创建Aspect,增加业务逻辑 ...
- iOS开发小技巧--获取自定义的BarButtonItem中的自定义View的方法(customView)
如果BarButtonItem是通过[[UIBarButtonItem alloc] initWithCustomView:(nonnull UIView *)]方法设置的.某些情况下需要修改BarB ...
- .net c#获取自定义Attribute
前言: 在c#开发中,有时候我们需要读取 Attribute中的信息(关于Attribute , 我自己把他理解成一个可以为类,属性标记的东西,这个标记可以为你提供一些关于类,方法,属性的额外信息) ...
- C# 如何获取自定义的config中节点的值,并修改节点的值
现定义一个方法 DIYConfigHelper.cs using System; using System.Xml; using System.Configuration; using System. ...
- day05 Spring中自定义注解的用处-之获取自定义的Servie
PS: 在RPC远程调用中,想要获取自定义的service的方法,就得自定义标签遍历拿到方法 PS:在spring中,两个最核心的 概念是aop和ioc,aop其实就是动态代理. ioc 就是解决对象 ...
- java反射机制获取自定义注解值和方法
由于工作需求要应用到java反射机制,就做了一下功能demo想到这些就做了一下记录 这个demo目的是实现动态获取到定时器的方法好注解名称,废话不多说了直接上源码 1.首先需要自定义注解类 /** * ...
- js ajax设置和获取自定义header信息的方法总结
目录 1.js ajax 设置自定义header 1.1 方法一: 1.2 方法二: 2.js ajax 获取请求返回的response的header信息 3.js ajax 跨域请求的情况下获取自定 ...
- AntDesign getFieldDecorator 获取自定义组件的值
AntDesign getFieldDecorator 获取自定义组件的值 1.自定义或第三方的表单控件,也可以与 Form 组件一起使用.只要该组件遵循以下的约定: (1)提供受控属性 value ...
随机推荐
- 【WebGIS系列】Typescript+WebGL+Webpack开发环境搭建
目前Web实现矢量渲染的主流技术包括SVG.VML和WebGL.相对而言,VML是一种较古老的技术,虽然未成为W3C标准,但被早期的IE浏览器(IE9以下)和微软Office广泛使用,目前已经远离了浏 ...
- DotNetCore跨平台~认识环境和环境变量
回到目录 环境 环境,对于开发来说就是部署的一种场景,你可以是调试场景,测试场景,生产场景,当然还可以有很多其它的场景,只要你的项目需要就可以自定义,微软帮我们定义了三种标准的环境变量,下面来说一下. ...
- 多元线性回归公式推导及R语言实现
多元线性回归 多元线性回归模型 实际中有很多问题是一个因变量与多个自变量成线性相关,我们可以用一个多元线性回归方程来表示. 为了方便计算,我们将上式写成矩阵形式: Y = XW 假设自变量维度为N W ...
- spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
前言 开心一刻 一名劫匪慌忙中窜上了一辆车的后座,上车后发现主驾和副驾的一男一女疑惑地回头看着他,他立即拔出枪威胁到:“赶快开车,甩掉后面的警车,否则老子一枪崩了你!”,于是副驾上的男人转过脸对那女的 ...
- Unity 3D游戏开发学习路线(方法篇)
Unity 3D本来是由德国的一些苹果粉丝开发的一款游戏引擎,一直只能用于Mac平台,所以一直不被业外人士所知晓.但是后来也推出了2.5版,同时发布了PC版本,并将其发布方向拓展到手持移动设备.Uni ...
- C# 提前异步加载数据
前言 在我们应用程序中,如果有较大的数据需要从数据库或者本地读取,且是一次性的话,可以提前获取数据并缓存在内存中. 一般处理方法:利用应用程序启动到用户使用功能这一段时间,提前加载数据. 问题来了,因 ...
- 前端性能核对表Checklist-2018
前端性能核对表Checklist-2018 1. 计划与度量 Get Ready: Planning and Metrics ☐ Establish a performance culture. ☐ ...
- Mysql使用event,类似oracle job
MySQL从5.1开始支持event功能,类似oracle的job功能.有了这个功能之后我们就可以让MySQL自动的执行数据汇总等功能,不用像以前需要操作的支持了.如linux crontab功能. ...
- Javascript之高级数组API的使用实例
JS代码中我们可以根据需求新建新的对象解决问题的同时,也有一些常用的内置对象供我们使用,我们称之为API,本篇文章只是对数组部分进行了练习. 例一:伪数组,不能修改长短的数组(所以没办法清零),可以修 ...
- css的三种书写方式
一.内联样式 <p style="color: sienna; margin-left: 20px"> This is a paragraph </p> 二 ...