最近在折腾IdentityServer4,为了简单,直接使用了官方给的QuickStart示例项目作为基础进行搭建。有一说一,为了保护一个API,感觉花费的时间比写一个API还要多。

本文基于ASP.NET CORE 3.1, IdentityServer4 3.1.3。代码皆为关键代码,贴全了太多了。

好不容易跑起来了,最终的任务要落实到授权的工作上来。在API中使用Authorize用来限制用户的访问。

[Route("api/[controller]")]
[Authorize(Roles = "Administrator")]
[ApiController]
public class UserInfoController : ControllerBase
{
/// <summary>
/// 无参GET请求
/// </summary>
/// <returns></returns>
[HttpGet()]
[ProducesResponseType(typeof(ReturnData<IEnumerable<UserInfo>>), Status200OK)]
public async Task<ActionResult> Get()
{
var info = new Info<UserInfo>();
return Ok(new ReturnData<IEnumerable<UserInfo>>(await info.Get()));
}

然而在使用的时候,虽然正确取得授权,但是却无法正常访问API,一直提示401没有授权错误。仔细检查,发现IdentityServer4返回的内容并没有返回role的JwtClaimTypes,没有它,Authorize无法正常工作。

{
"nbf": 1587301921,
"exp": 1587305521,
"iss": "http://localhost:5000",
"aud": "MonitoringSystemApi",
"client_id": "webClient",
"sub": "c6c18d4d-c28e-4de5-86dd-779121216204",
"auth_time": 1587301921,
"idp": "local",
"scope": [
"roles",
"MonitoringSystemApi",
"offline_access"
],
"amr": [
"pwd"
]
}

实现

查看Config.cs,IdentityServer4默认只返回两种IdentityResource:openid和profile。按照官方的说法,这个东西定义的内容会返回到用户的token。参考。那么就果断给它安排。

public static IEnumerable<IdentityResource> Ids =>
new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource ("roles", new List<string> { JwtClaimTypes.Role }){ Required = true}
}; public static IEnumerable<Client> Clients =>
new List<Client>
{
new Client
{
ClientId = "webClient",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowOfflineAccess = true,
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
// scopes that client has access to
AllowedScopes = {
"roles", "MonitoringSystemApi" }
},

执行之前,需要确保数据库中的用户数据,已经包含role的Claim。

//添加用户代码
bob = new ApplicationUser
{
UserName = "bob"
};
var result = userMgr.CreateAsync(bob, "Pass123$").Result;
if (!result.Succeeded)
{
throw new Exception(result.Errors.First().Description);
}
result = userMgr.AddClaimsAsync(bob, new Claim[]{
new Claim(JwtClaimTypes.Role, "Administrator"),
new Claim(JwtClaimTypes.Name, "Bob Smith"),

运行程序,返回值依旧没有任何变化,很挫败,只能继续折腾。

研究通过实现IProfileService达到自定义Cliams。文章写的很详细,我这就不重复了,我实际试验过,可以成功。

但是文章末尾的注意,很重要。

“那么, 通过profileservice颁发的claims, 任意clients都能拿到”

说明这个优先级是非常高的,可以覆盖所有的行为,当然我们可以在IProfileService的实现上对权限进行进一步的设置,不过还是挺麻烦的。参考实现参考官方

作为懒人,必然不想再费劲去折腾权限的问题,那么是否有简单点的办法呢?

网上有一些问答说到了可以通过设置Scopes来达到目的。不过过于久远,IdentityServer4已经没有这个独立的类了,说是已经被ApiResource取代了。

直觉上这个东西应该是指示要保护的API的相关内容的,好像和这个没啥关系,不过也只能死马当活马医了。修改config.cs,最终如下内容:

public static IEnumerable<ApiResource> Apis =>
new List<ApiResource>
{
new ApiResource("pls", new[]{ "role"}),
}; public static IEnumerable<Client> Clients =>
new List<Client>
{
new Client
{
ClientId = "webClient",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowOfflineAccess = true,
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
// scopes that client has access to
AllowedScopes = {
"pls"
}
},

返回结果如下:

{
"nbf": 1587301799,
"exp": 1587305399,
"iss": "http://localhost:5000",
"aud": "pls",
"client_id": "webClient",
"sub": "c6c18d4d-c28e-4de5-86dd-779121216204",
"auth_time": 1587301799,
"idp": "local",
"role": "Administrator",
"scope": [
"pls",
"offline_access"
],
"amr": [
"pwd"
]
}

终于看见心心念念的自定义Claim(role),可以去访问API了。

注意,在Client中也有个Claims,添加了role并且设置AlwaysSendClientClaimsAlwaysIncludeUserClaimsInIdToken之后,会在token中添加client_roie字段,这个是没办法用与授权的,可以理解为IdentityServer4直接指定了Client角色,并不是Identity中的角色概念。

后记

回过头来仔细看官方的文档,ApiResource中的UserClaims就是用来干这个的,折腾了半天,不如当时仔细看看文档了。

IdentityServer4 QuckStart 授权与自定义Claims的更多相关文章

  1. IdentityServer4客户端如何获取自定义声明,了解一下?

    前言 久违了各位,之前录制过IdentityServer4的基础视频(https://space.bilibili.com/319652230/#/),有兴趣了解的童鞋可以看一下,只不过未发表成博客. ...

  2. 【.NET Core项目实战-统一认证平台】第十四章 授权篇-自定义授权方式

    [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我介绍了如何强制令牌过期的实现,相信大家对IdentityServer4的验证流程有了更深的了解,本篇我将介绍如何使用自定义的授权方 ...

  3. .net core Identity集成IdentityServer(2) 实现IprofileService接口在accesstoken中增加自定义claims

    导读 1. 如何添加自定义的claims. 前请提要 目前我们拥有了三个web应用. localhost:40010, 验证服务器 localhost:40011, mvc客户端, 充当webapp请 ...

  4. Asp.net Core 系列之--5.认证、授权与自定义权限的实现

    ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...

  5. IdentityServer4 (3) 授权码模式(Authorization Code)

    写在前面 1.源码(.Net Core 2.2) git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git 2.相关章节 2.1. ...

  6. 一看就懂的IdentityServer4认证授权设计方案

    查阅了大多数相关资料,总结设计一个IdentityServer4认证授权方案,我们先看理论,后设计方案. 1.快速理解认证授权 我们先看一下网站发起QQ认证授权,授权通过后获取用户头像,昵称的流程. ...

  7. spring security 授权方式(自定义)及源码跟踪

    spring security 授权方式(自定义)及源码跟踪 ​ 这节我们来看看spring security的几种授权方式,及简要的源码跟踪.在初步接触spring security时,为了实现它的 ...

  8. 认证授权:IdentityServer4 - 各种授权模式应用

    前言: 前面介绍了IdentityServer4 的简单应用,本篇将继续讲解IdentityServer4 的各种授权模式使用示例 授权模式: 环境准备 a)调整项目结构如下:   b)调整cz.Id ...

  9. IdentityServer4系列 | 授权码模式

    一.前言 在上一篇关于简化模式中,通过客户端以浏览器的形式请求IdentityServer服务获取访问令牌,从而请求获取受保护的资源,但由于token携带在url中,安全性方面不能保证.因此,我们可以 ...

随机推荐

  1. Cisco 综合配置(一)

    要求: 1.内网所有PC及服务器都能访问外网 2.外网通过公网地址 202.101.100.3 访问内网服务器的Telnet服务 配置: PC.服务器都配置好自己的IP和默认网关:192.168.1. ...

  2. 第四周java实验

    实验四 类与对象的定义及使用 实验时间 2018-9-20 1.实验目的与要求 (1) 理解用户自定义类的定义: 类是具有相同属性和行为的一组对象的集合.java中,用构造器构造并初始化对象. 类是构 ...

  3. Prism 源码解读3-Modules加载

    介绍 在软件开发过程中,总想组件式的开发方式,各个组件之间最好互不影响,独立测试.Prism的Modules很好的满足了这一点. 这个架构图很好了讲解了Prism的Modules的概念 Prism支持 ...

  4. go:数据类型

    Go语言中有丰富的数据类型,除了基本的整型.浮点型.布尔型.字符串外,还有数组.切片.结构体.函数.map.通道(channel)等.Go 语言的基本类型和其他语言大同小异. 1.基本数据类型 整型 ...

  5. 强化学习之三点五:上下文赌博机(Contextual Bandits)

    本文是对Arthur Juliani在Medium平台发布的强化学习系列教程的个人中文翻译,该翻译是基于个人分享知识的目的进行的,欢迎交流!(This article is my personal t ...

  6. [LeetCode] 937. Reorder Data in Log Files 日志文件的重新排序

    You have an array of `logs`.  Each log is a space delimited string of words. For each log, the first ...

  7. 三层架构——ATM + 购物车

    三层架构:用户视图层.逻辑接口层.数据处理层. 一个功能,分成三层架构写,增加程序的可扩展性. 三层是互有联系的,从用户视图层开始写,涉及到那一层就到下一层去写,然后return 返回值,再写回来. ...

  8. VS2015 远程调试:Remote Debugger

    一.关于Remote Debugger 使用VS远程调试器Remote Debugger,我们可以调试部署在不同机器上的应用程序,如桌面应用程序和Asp.Net应用程序. 二.Remote Debug ...

  9. Activiti任务分配

    分配任务负责人 一.固定分配 在进行业务流程建模时指定固定的任务负责人 在properties 视图中,填写Assignee 项为任务负责人. 注意: 由于固定分配方式,任务只管一步一步执行任务,执行 ...

  10. css指示箭头两种实现方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...