如何将Asp.net core IdentityServer4与角色权限系统无缝集成?

2026-05-25 12:561阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1151个文字,预计阅读时间需要5分钟。

如何将Asp.net core IdentityServer4与角色权限系统无缝集成?

在封面+因为最近太忙了,好久没水文了+今天来水一篇;在学习和或做权限系统技术选型的过程中,经常有朋友有这样的疑问:+IdentityServer4的能不能做到与传统基于角色的权限控制?

写在前面

因为最近在忙别的,好久没水文了 今天来水一篇;

在学习或者做权限系统技术选型的过程中,经常有朋友有这样的疑问 :

“IdentityServer4的能不能做到与传统基于角色的权限系统集成呢?”

“我的公司有几百个接口,IdentityServer4能不能做到关联用户,给这些用户授予不同的接口的权限呢?”

我的回答是:是的,可以!

同时,我还想补充下,IdentityServer4是给我们的授权流程/需求提供一个新的 标准化的选择,而不是限制你的需求;它是一个基础的框架,你可以根据你的需求自定义成任意你要的样子。

OK,下面开始说说我的实现思路,不一定最优只为抛砖引玉。

开始之前

先准备好两个WebApi 项目,分别有两个接口

Hei.UserApi:6001

GetUsername: localhost:6001/api/profile/getusername

GetScore: localhost:6001/api/Credit/GetScore //用户信用分要求高,期望管理员才可以调用

Hei.OrderApi:6002

GetOrderNo:localhost:6002/api/Order/GetOrderNo

GetAddress: localhost:6002/api/Delivery/GetAddress //用户地址敏感,期望管理员才可以调用

实现请看源码

准备好两个角色:

R01 管理员

R02 普通用户

准备好两个用户

Bob: subid=1001,普通用户

Alice: subid=1002,管理员

实际用户有多个角色的,本文为了简化问题,一个用户只允许一种角色

角色对应的权限

管理员:可以调用 Hei.UserApiHei.OrderApi的所有接口;

普通用户:只可以调用 Hei.UserApi->GetUsername,和Hei.OrderApi->GetOrderNo;

实现思路

先来看晓晨大佬画的 access_token 验证交互过程图:

可以看到,Token在首次被服务端验证后,后续的验证都在客户端验证的,本文的重点就在这里,需要判断token有没有权限,重写这部分即可;

开始实现 服务端 1、生成自定义token

1、 IdentityServer4 服务端重写IResourceOwnerPasswordValidatorIProfileService 两个接口生成携带有自定义信息的access_token

public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { public CustomResourceOwnerPasswordValidator() { } public Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { if (!string.IsNullOrEmpty(context.UserName) && !string.IsNullOrEmpty(context.Password)) { var loginUser = UserService.Users.First(c => c.Username == context.UserName && c.Password == context.Password); if (loginUser != null) { context.Result = new GrantValidationResult(loginUser.SubjectId, OidcConstants.AuthenticationMethods.Password, new Claim[]{new Claim("my_phone","10086")}); //这里增加自定义信息 return Task.CompletedTask; } } return Task.CompletedTask; } }

StartUp.cs 启用

builder.AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>(); builder.AddProfileService<CustomProfileService>();

2、请求一个token来看看:

可以看到我这里token携带有了自定义信息 my_phone,同样的,你可以把角色id直接放这里,或者直接跟用户的subid关联(本demo就是);

客户端 1、自定义授权标签CustomRBACAuthorize

public class CustomRBACAuthorizeAttribute : AuthorizeAttribute { public CustomRBACAuthorizeAttribute(string policyName="") { this.PolicyName = policyName; } public string PolicyName { get { return PolicyName; } set { Policy = $"{Const.PolicyCombineIdentityServer4ExternalRBAC}{value.ToString()}"; } } }

后面接口打这个标签就表示使用基于自定义的与权限校验

如何将Asp.net core IdentityServer4与角色权限系统无缝集成?

2、自定义授权 IAuthorizationRequirement

public class CustomRBACRequirement: IAuthorizationRequirement { public string PolicyName { get; } public CustomRBACRequirement(string policyName) { this.PolicyName = policyName; } } 3、自定义IAuthorizationPolicyProvider

public class CustomRBACPolicyProvider : IAuthorizationPolicyProvider { private readonly IConfiguration _configuration; public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } public CustomRBACPolicyProvider(IConfiguration configuration, IOptions<AuthorizationOptions> options) { _configuration = configuration; FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); } public Task<AuthorizationPolicy> GetDefaultPolicyAsync() { return FallbackPolicyProvider.GetDefaultPolicyAsync(); } public Task<AuthorizationPolicy> GetFallbackPolicyAsync() { return Task.FromResult<AuthorizationPolicy>(null); } public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if (policyName.StartsWith(Const.PolicyCombineIdentityServer4ExternalRBAC, StringComparison.OrdinalIgnoreCase)) { var policys = new AuthorizationPolicyBuilder(); //这里使用自定义Requirement policys.AddRequirements(new CustomRBACRequirement(policyName.Replace(Const.PolicyCombineIdentityServer4ExternalRBAC,""))); return Task.FromResult(policys.Build()); } return Task.FromResult<AuthorizationPolicy>(null); } } 4、自定义Requirement的的 AuthorizationHandler

/// <summary> /// 处理CustomRBACRequirement的逻辑 /// </summary> /// <param name="context"></param> /// <param name="requirement"></param> /// <returns></returns> protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRBACRequirement requirement) { var subid = context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; var routeData = _github.com/gebiWangshushu/cnblogs-demos/tree/dev/IdentityServerWithRBAC.Example

如果能有个小星星那就再好不过了(✧◡✧)

参考

docs.microsoft.com/zh-cn/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-3.1#multiple-authorization-policy-providers

www.cnblogs.com/stulzq/p/9226059.html

本文共计1151个文字,预计阅读时间需要5分钟。

如何将Asp.net core IdentityServer4与角色权限系统无缝集成?

在封面+因为最近太忙了,好久没水文了+今天来水一篇;在学习和或做权限系统技术选型的过程中,经常有朋友有这样的疑问:+IdentityServer4的能不能做到与传统基于角色的权限控制?

写在前面

因为最近在忙别的,好久没水文了 今天来水一篇;

在学习或者做权限系统技术选型的过程中,经常有朋友有这样的疑问 :

“IdentityServer4的能不能做到与传统基于角色的权限系统集成呢?”

“我的公司有几百个接口,IdentityServer4能不能做到关联用户,给这些用户授予不同的接口的权限呢?”

我的回答是:是的,可以!

同时,我还想补充下,IdentityServer4是给我们的授权流程/需求提供一个新的 标准化的选择,而不是限制你的需求;它是一个基础的框架,你可以根据你的需求自定义成任意你要的样子。

OK,下面开始说说我的实现思路,不一定最优只为抛砖引玉。

开始之前

先准备好两个WebApi 项目,分别有两个接口

Hei.UserApi:6001

GetUsername: localhost:6001/api/profile/getusername

GetScore: localhost:6001/api/Credit/GetScore //用户信用分要求高,期望管理员才可以调用

Hei.OrderApi:6002

GetOrderNo:localhost:6002/api/Order/GetOrderNo

GetAddress: localhost:6002/api/Delivery/GetAddress //用户地址敏感,期望管理员才可以调用

实现请看源码

准备好两个角色:

R01 管理员

R02 普通用户

准备好两个用户

Bob: subid=1001,普通用户

Alice: subid=1002,管理员

实际用户有多个角色的,本文为了简化问题,一个用户只允许一种角色

角色对应的权限

管理员:可以调用 Hei.UserApiHei.OrderApi的所有接口;

普通用户:只可以调用 Hei.UserApi->GetUsername,和Hei.OrderApi->GetOrderNo;

实现思路

先来看晓晨大佬画的 access_token 验证交互过程图:

可以看到,Token在首次被服务端验证后,后续的验证都在客户端验证的,本文的重点就在这里,需要判断token有没有权限,重写这部分即可;

开始实现 服务端 1、生成自定义token

1、 IdentityServer4 服务端重写IResourceOwnerPasswordValidatorIProfileService 两个接口生成携带有自定义信息的access_token

public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { public CustomResourceOwnerPasswordValidator() { } public Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { if (!string.IsNullOrEmpty(context.UserName) && !string.IsNullOrEmpty(context.Password)) { var loginUser = UserService.Users.First(c => c.Username == context.UserName && c.Password == context.Password); if (loginUser != null) { context.Result = new GrantValidationResult(loginUser.SubjectId, OidcConstants.AuthenticationMethods.Password, new Claim[]{new Claim("my_phone","10086")}); //这里增加自定义信息 return Task.CompletedTask; } } return Task.CompletedTask; } }

StartUp.cs 启用

builder.AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>(); builder.AddProfileService<CustomProfileService>();

2、请求一个token来看看:

可以看到我这里token携带有了自定义信息 my_phone,同样的,你可以把角色id直接放这里,或者直接跟用户的subid关联(本demo就是);

客户端 1、自定义授权标签CustomRBACAuthorize

public class CustomRBACAuthorizeAttribute : AuthorizeAttribute { public CustomRBACAuthorizeAttribute(string policyName="") { this.PolicyName = policyName; } public string PolicyName { get { return PolicyName; } set { Policy = $"{Const.PolicyCombineIdentityServer4ExternalRBAC}{value.ToString()}"; } } }

后面接口打这个标签就表示使用基于自定义的与权限校验

如何将Asp.net core IdentityServer4与角色权限系统无缝集成?

2、自定义授权 IAuthorizationRequirement

public class CustomRBACRequirement: IAuthorizationRequirement { public string PolicyName { get; } public CustomRBACRequirement(string policyName) { this.PolicyName = policyName; } } 3、自定义IAuthorizationPolicyProvider

public class CustomRBACPolicyProvider : IAuthorizationPolicyProvider { private readonly IConfiguration _configuration; public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } public CustomRBACPolicyProvider(IConfiguration configuration, IOptions<AuthorizationOptions> options) { _configuration = configuration; FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); } public Task<AuthorizationPolicy> GetDefaultPolicyAsync() { return FallbackPolicyProvider.GetDefaultPolicyAsync(); } public Task<AuthorizationPolicy> GetFallbackPolicyAsync() { return Task.FromResult<AuthorizationPolicy>(null); } public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if (policyName.StartsWith(Const.PolicyCombineIdentityServer4ExternalRBAC, StringComparison.OrdinalIgnoreCase)) { var policys = new AuthorizationPolicyBuilder(); //这里使用自定义Requirement policys.AddRequirements(new CustomRBACRequirement(policyName.Replace(Const.PolicyCombineIdentityServer4ExternalRBAC,""))); return Task.FromResult(policys.Build()); } return Task.FromResult<AuthorizationPolicy>(null); } } 4、自定义Requirement的的 AuthorizationHandler

/// <summary> /// 处理CustomRBACRequirement的逻辑 /// </summary> /// <param name="context"></param> /// <param name="requirement"></param> /// <returns></returns> protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRBACRequirement requirement) { var subid = context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; var routeData = _github.com/gebiWangshushu/cnblogs-demos/tree/dev/IdentityServerWithRBAC.Example

如果能有个小星星那就再好不过了(✧◡✧)

参考

docs.microsoft.com/zh-cn/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-3.1#multiple-authorization-policy-providers

www.cnblogs.com/stulzq/p/9226059.html