Asp.Net Core 中IdentityServer4 实战之角色授权详解
Jlion 人气:0
## 一、前言
前几篇文章分享了`IdentityServer4`密码模式的基本授权及自定义授权等方式,最近由于改造一个网关服务,用到了`IdentityServer4`的授权,改造过程中发现比较适合基于`Role`角色的授权,通过不同的角色来限制用户访问不同的`Api资源`,这里我就来分享`IdentityServer4`基于角色的授权详解。
#### IdentityServer4 历史文章目录
- [Asp.Net Core IdentityServer4 中的基本概念](https://www.cnblogs.com/jlion/p/12437441.html)
- [Asp.Net Core 中IdentityServer4 授权中心之应用实战](https://www.cnblogs.com/jlion/p/12447081.html)
- [Asp.Net Core 中IdentityServer4 授权中心之自定义授权模式](https://www.cnblogs.com/jlion/p/12468365.html)
- [Asp.Net Core 中IdentityServer4 授权原理及刷新Token的应用](https://www.cnblogs.com/jlion/p/12501195.html)
- [Asp.Net Core 中IdentityServer4 实战之 Claim详解](https:////www.cnblogs.com/jlion/p/12543486.html)
没有看过之前的几篇文章,我建议先回过头看看上面那几篇文章再来看本篇文章,不过对于大牛来说就可以跳过了。。。。
## 二、模拟场景
还是按照我的文章风格套路,实战之前先来模拟下应用场景,无场景的实战都是耍流氓,模拟场景更能让大家投入,同时也是自我学习、思考、总结的结晶之处!!!
对于角色授权大家也不陌生,大家比较熟悉的应该是`RBAC`的设计,这里就不阐述`RBAC`,有兴趣的可以百度。我们这里简单模拟下角色场景
假如有这么一个`数据网关服务`服务(下面我统称为`数据网关`),客户端有三种账号角色(普通用户、管理员用户、超级管理员用户),数据网关针对这三种角色用户分配不同的数据访问权限,场景图如下:
![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200328175216974-1045194802.jpg)
那么这种场景我们会怎么去设计呢?这个场景还算比较简单,角色比较单一,比较固定,对于这种场景很多人可能会考虑到通过`Filter`过滤器等方式来实现,这当然可以。不过正对这种场景`IdentityServer4`中本身就支持角色授权,下面我来给大家分享`IdentityServer4`的角色授权.
## 三、角色授权实战
#### 授权流程
撸代码之前我们先整理下`IdentityServer4`的 角色授权流程图,我简单概括画了下,流程图如下:
![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200328175347833-226144972.jpg)
场景图概括如下:
- 客户端分为三种核心角色(普通用户、管理员用户、超级管理-老板)用户,三种用户访问同一个`数据网关`(API资源)
- `数据网关`(API资源)对这三种用户角色做了访问限制。
角色授权流程解释如下:
- 第一步: 不同的用户携带用户密码等信息访问`授权中心`(ids4)尝试授权
- 第二步: `授权中心`对用户授权通过返回`access_token`给用户同时声明用户的`Role`到`Claim`中。。
- 第三步: 客户端携带拿到的`access_token`尝试请求`数据网关`(API资源)。
- 第四步:`数据网关`收到客户端的第一次请求会到`授权中心`请求获得验证公钥。
- 第五步:`授权中心`返回`验证公钥`给`数据网关`并且缓存起来,后面不再到`授权中心`再次获得验证公钥(只会请求一次,除非重启服务)。
- 第六步:`数据网关`(ids4)通过验证网关验证`access_token`是否验证通过,并且验证请求的客户端用户声明的`Role`是否和请求的`API资源`约定的的角色一致。如果一致则通过第步返回给用户端,否则直接拒绝请求.
#### 撸代码
代码继续上面几篇文章的例子的续集,你懂的,就不从零开始撸代码啦(强烈建议没看过上面几篇的先看下上面的目录中的几篇,要不然会一头雾水,大佬跳过)
要使`IdentityServer4`实现的`授权中心`支持角色验证的支持,我们需要在定义的`API资源`中添加`角色`的引入,代码如下:
上几篇文章的`授权中心`(Jlion.NetCore.Identity.Service)的
代码如下:
```
///
/// 资源
///
///
public static IEnumerable GetApiResources()
{
return new List
{
new ApiResource(OAuthConfig.UserApi.ApiName,OAuthConfig.UserApi.ApiName),
};
}
```
加入角色的支持代码改造如下:
```
///
/// 资源
///
///
public static IEnumerable GetApiResources()
{
return new List
{
new ApiResource(
OAuthConfig.UserApi.ApiName,
OAuthConfig.UserApi.ApiName,
new List(){JwtClaimTypes.Role }
),
};
}
```
`API资源`中添加了`角色`验证的支持后,需要在用户登录授权成功后声明Claim用户的`Role`信息,代码如下:
改造前代码:
```
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
try
{
var userName = context.UserName;
var password = context.Password;
//验证用户,这么可以到数据库里面验证用户名和密码是否正确
var claimList = await ValidateUserAsync(userName, password);
// 验证账号
context.Result = new GrantValidationResult
(
subject: userName,
authenticationMethod: "custom",
claims: claimList.ToArray()
);
}
catch (Exception ex)
{
//验证异常结果
context.Result = new GrantValidationResult()
{
IsError = true,
Error = ex.Message
};
}
}
#region Private Method
///
/// 验证用户
///
///
///
///
private async Task
- > ValidateUserAsync(string loginName, string password)
{
//TODO 这里可以通过用户名和密码到数据库中去验证是否存在,
// 以及角色相关信息,我这里还是使用内存中已经存在的用户和密码
var user = OAuthMemoryData.GetTestUsers();
if (user == null)
throw new Exception("登录失败,用户名和密码不正确");
return new List
- > ValidateUserByRoleAsync(string loginName, string password)
{
//TODO 这里可以通过用户名和密码到数据库中去验证是否存在,
// 以及角色相关信息,我这里还是使用内存中已经存在的用户和密码
var user = OAuthMemoryData.GetUserByUserName(loginName);
if (user == null)
throw new Exception("登录失败,用户名和密码不正确");
//下面的Claim 声明我为了演示,硬编码了,
//实际生产环境需要通过读取数据库的信息并且来声明
return new List
加载全部内容