咨询热线:15536182553 联系人:孔祥东 地址:吉林省松原市宁江区沿江路
IdentityServer4客户端如何获取自定义声明,了解一下?
来源:同乐城备用网址 发布时间:2019-11-22 点击量:366
前言
久违了各位,之前录制过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(0); } public Task IsActiveAsync(IsActiveContext context) { var user = _userManager.GetUserAsync(context.Subject).Result; context.IsActive = true; return Task.FromResult(0); } }
接下来在注入IdentityServer4时,添加我们自定义实现的ProfileService,更多基础请参考IdentityServer4官网以及我所录制的IdentityServer4基础视频。
//注入IdentityServer4使用AspNetIdentity services.AddIdentityServer(options => { options.Authentication.CookieLifetime = TimeSpan.FromMinutes(1); }) .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所产生的副作用,感谢阅读,若有不同见解,望留下您的评论。
相关产品
-
实际运营数据显示,目前我市运营的节能与新能源公交车,一年节油近千万升,减少二氧化碳排放70537.5吨,环保指标完全达到两型社会的要求。
-
湖南省副省长向力力表示,此次签约项目既能表达毛主席对家乡韶山的牵挂,又能表达韶山是中国共产党人的精神根基、力量源泉、信仰高地,是“继续前行”的“初心”所在。“最忆”与“不忘初心”内涵高度契合,有利于我们讲好毛主席的故事,传承红色经典,弘扬红色文化。项目的建成,也将带动韶山文化旅游产业发展,为湖南建设全域旅游基地、全力塑造“锦绣潇湘”旅游品牌提供有力支撑。
-
“我们知道,中医讲究望闻问切,西医注重视触叩听,这是医术的‘灵魂’,而远程会诊技术只能完成‘问’和部分‘视’,切不着,闻不见,叩不成,触不到,就好比丢了‘灵魂’。”胡晓翔表示,因此,慢性病的复诊患者如果不方便去医院,可以尝试专家的视频问诊,不过前提一定是该医生全面掌握了你的健康信息。
-
据悉,在这一高强度的辐射量下数十秒即可致人死亡,证实发生事故的反应堆内情况极为严重的同时,再次凸显反应堆报废作业中取出燃料碎片的难度之大。计划在2月下旬前进行的由附带摄像头的自动行走机器人实施的正式调查有可能面临相当大的困难。
-
释延鲁称,除此之外释永信还多次向他索取财物。其中一次是2006年9月11日,释永信让司机庞超找他买辆奔驰商务车做接待,于是他在河南华星汽车贸易有限 公司购买了一辆19万的奔驰。后来又让庞超拿着购车发票,由他签字后向寺院财务报销,但报销款并没有还给释延鲁,而是据为己有。“释永信不但白得了一辆车,还侵吞寺院资金19万。”
-
“递延纳税是国际通行的一种养老保险税收优惠模式。”施正文表示,所谓递延纳税,是指在个人缴费和账户资金收益环节暂不征收个人所得税,将纳税义务递延到个人领取商业养老金环节。
-
2018款昂科威采用了全新的家族式设计语言,标志性的飞翼式前进气格栅自然也没有缺席,前进气格栅外侧的镀铬装饰条与中央的LOGO相互呼应,呈现出一体式的美感。同时,保险杠下方两侧的雾灯采用了全新设计的“C”字造型,相比现款更加时尚。
-
很多人都听说过这么一句话,“恋爱中的人智商为零”。可现实中,太多人陷入恋情后反而会变得更加敏感细腻、观察入微。本周六晚(4月29日)《非诚勿扰》,一位男嘉宾提出,“恋爱中大家都是‘福尔摩斯’,就看谁更胜一筹了。”此话一出,随即引发了热烈讨论。黄澜则表态:“所谓恋爱中的‘福尔摩斯’,能不能把‘侦查’对方的精力放在照顾对方的情绪上?当对方有情绪波动的时候多去关心了解,而不要等到对方想要离开的时候,再花精力去查,那就没有意义了。”
热点资讯
- 女主持节目拿被斩首狗头给观众了一个真实的噩梦2019-11-15
- 可爱贴心/礼物首选,5600mAh天使与恶魔暖手宝/充电宝89元2019-11-21
- 通过wireshark抓包来讲解HTTP中Connection:keep-alive头部的作用2019-06-23
- 你了解节叶灯心草多少节叶灯心草知识大全2019-11-07
- 董秘解码:苏大维格攻克“纳米波导光场镜片”批量化关键技术2019-11-14
- 小米公布PocophoneF1手机价格:8GB+256GB不到3000元2019-06-23
- 石家庄1号公司发生爆炸事故:拆除管道|管道|石家庄|石家庄市造成可燃气体残留2019-10-29
- 特朗普拒绝妥协:没有边界墙,政府不会重新开放!2019-10-30