前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >使用.NET从零实现基于用户角色的访问权限控制

使用.NET从零实现基于用户角色的访问权限控制

作者头像
桑榆肖物
发布于 2022-11-18 02:21:05
发布于 2022-11-18 02:21:05
1.7K00
代码可运行
举报
文章被收录于专栏:桑榆肖物桑榆肖物
运行总次数:0
代码可运行

使用.NET从零实现基于用户角色的访问权限控制

本文将介绍如何实现一个基于.NET RBAC 权限管理系统,如果您不想了解原理,可查看推送的另一篇文章关于Sang.AspNetCore.RoleBasedAuthorization[1] 库是使用介绍,直接使用该库即可。

背景

在设计系统时,我们必然要考虑系统使用的用户,不同的用户拥有不同的权限。主流的权限管理系统都是RBAC模型(Role-Based Access Control 基于角色的访问控制)的变形和运用,只是根据不同的业务和设计方案,呈现不同的显示效果。

在微软文档中我们了解了《基于角色的授权》[2],但是这种方式在代码设计之初,就设计好了系统角色有什么,每个角色都可以访问哪些资源。针对简单的或者说变动不大的系统来说这些完全是够用的,但是失去了灵活性。因为我们不能自由的创建新的角色,为其重新指定一个新的权限范围,毕竟就算为用户赋予多个角色,也会出现重叠或者多余的部分。

RBAC(Role-Based Access Control)即:基于角色的权限控制。通过角色关联用户,角色关联权限的方式间接赋予用户权限。

RBAC模型可以分为:RBAC0、RBAC1、RBAC2、RBAC3 四种。其中RBAC0是基础,也是最简单的,今天我们就先从基础的开始。

资源描述的管理

在开始权限验证设计之前我们需要先对系统可访问的资源进行标识和管理。在后面的权限分配时,我们通过标识好的资源进行资源和操作权限的分配。

资源描述

创建一个 ResourceAttribute 继承 AuthorizeAttributeIAuthorizationRequirement 资源描述属性,描述访问的角色需要的资源要求。通过转化为 Policy 来对 策略的授权[3] 提出要求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class ResourceAttribute: AuthorizeAttribute, IAuthorizationRequirement
{
    private string _resouceName;
    private string? _action;
    /// <summary>
    /// 设置资源类型
    /// </summary>
    /// <param name="name">资源名称</param>
    /// <exception cref="ArgumentNullException">资源名称不能为空</exception>
    public ResourceAttribute(string name)
    {
        if (string.IsNullOrEmpty(name))
        {
            throw new ArgumentNullException(nameof(name));
        }
        string[] resourceValues = name.Split('-');
        _resouceName = resourceValues[0];
        if (resourceValues.Length > 1)
        {
            Action = resourceValues[1];
        }
        else
        {
            Policy = resourceValues[0];
        }
    }

    /// <summary>
    /// 获取资源名称
    /// </summary>
    /// <returns></returns>
    public string GetResource()
    {
        return _resouceName;
    }

    /// <summary>
    /// 获取操作名称
    /// </summary>
    public string? Action
    {
        get
        {
            return _action;
        }
        set
        {
            _action = value;
            if (!string.IsNullOrEmpty(value))
            {
                //把资源名称跟操作名称组装成Policy
                Policy = _resouceName + "-" + value;
            }
        }
    }
}

获得所有资源

我们标识好系统中的资源后,还需要获取到我们最终程序中都标识有哪些资源,这里就需使用 ASP.NET Core 中的应用程序模型[4]。可以在程序启动时获取到所有的 Controller 和 Controller 中的每一个方法,然后通过查询 ResourceAttribute 将其统一存储到静态类中。

创建一个 ResourceInfoModelProvider 继承 IApplicationModelProvider,其执行顺序我们设置为=> -989。其执行顺序:

•首先 (Order=-1000):DefaultApplicationModelProvider•然后(Order= -990):AuthorizationApplicationModelProvider CorsApplicationModelProvider•接着是这个 ResourceInfoModelProvider

其核心代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// 基于其 Order 属性以倒序调用
/// </summary>
/// <param name="context"></param>
public void OnProvidersExecuted(ApplicationModelProviderContext context)
{
    if (context == null)
    {
        throw new ArgumentNullException(nameof(context));
    }
    //获取所有的控制器
    List<ResourceAttribute> attributeData = new List<ResourceAttribute>();
    foreach (var controllerModel in context.Result.Controllers)
    {
        //得到ResourceAttribute

        //Controller 的特性
        var resourceData = controllerModel.Attributes.OfType<ResourceAttribute>().ToArray();
        if (resourceData.Length > 0)
        {
            attributeData.AddRange(resourceData);
        }
        //Controller 中的每个方法的特性
        foreach (var actionModel in controllerModel.Actions)
        {
            var actionResourceData = actionModel.Attributes.OfType<ResourceAttribute>().ToArray();
            if (actionResourceData.Length > 0)
            {
                attributeData.AddRange(actionResourceData);
            }
        }
    }
    // 整理信息集中存入全局
    foreach (var item in attributeData)
    {
        ResourceData.AddResource(item.GetResource(), item.Action);
    }
}

授权控制的实现

接下来我们要对授权控制来进行编码实现,包含自定义授权策略的实现和自定义授权处理程序。

动态添加自定义授权策略

关于自定义授权策略提供程序[5]的说明,这里不再赘述微软的文档,里面已经介绍了很详细,这里我们通过其特性可以动态的创建自定义授权策略,在访问资源时我们获取到刚刚标识的 Policy 没有处理策略,就直接新建一个,并传递这个策略的权限检查信息,当然这只是一方面,更多妙用,阅读文档里面其适用范围的说明即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// 自定义授权策略
/// 自动增加 Policy 授权策略
/// </summary>
/// <param name="policyName">授权名称</param>
/// <returns></returns>
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
    // 检查这个授权策略有没有
    AuthorizationPolicy? policy = _options.GetPolicy(policyName);

    if (policy is null)
    {
        _options.AddPolicy(policyName, builder =>
        {
            builder.AddRequirements(new ResourceAttribute(policyName));
        });
    }

    return Task.FromResult(_options.GetPolicy(policyName));
}

授权处理程序

前面我们已经可以动态创建授权的策略,那么关于授权策略的处理[6]我们可以实现 AuthorizationHandler 根据传递的策略处理要求对本次请求进行权限的分析。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
internal class ResourceAuthorizationHandler : AuthorizationHandler<ResourceAttribute>
{
    /// <summary>
    /// 授权处理
    /// </summary>
    /// <param name="context">请求上下文</param>
    /// <param name="requirement">资源验证要求</param>
    /// <returns></returns>
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ResourceAttribute requirement)
    {
        // 需要有用户
        if (context.User is null) return Task.CompletedTask;


        if (context.User.IsInRole(ResourceRole.Administrator) // 超级管理员权限,拥有 SangRBAC_Administrator 角色不检查权限
            || CheckClaims(context.User.Claims, requirement) // 符合 Resource 或 Resource-Action 组合的 Permission
            )
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;

    }

    /// <summary>
    /// 检查 Claims 是否符合要求
    /// </summary>
    /// <param name="claims">待检查的claims</param>
    /// <param name="requirement">检查的依据</param>
    /// <returns></returns>
    private bool CheckClaims(IEnumerable<Claim> claims, ResourceAttribute requirement)
    {
        return claims.Any(c =>
                    string.Equals(c.Type, ResourceClaimTypes.Permission, StringComparison.OrdinalIgnoreCase)
                    && (string.Equals(c.Value, requirement.GetResource(), StringComparison.Ordinal)
                    || string.Equals(c.Value, $"{requirement.GetResource()}-{requirement.Action}", StringComparison.Ordinal))
                    );
    }
}

这里我们提供了一个内置固定角色名的超级管理员用户,其请求不进行权限检查。

最后

这里我们已经实现了简单的 RBAC 权限设计,之后我们主要在生成 JWT 时带上可访问资源的Permission即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new Claim(ResourceClaimTypes.Permission,"查询")

当然,如果直接放在 jwt 中会让 Token 变得很长,虽然我其实并不理解微软的 ClaimTypes 使用一个URI标识,如果有了解的朋友可以帮我解个惑,万分感谢 https://stackoverflow.com/questions/72293184/ 。

回到这个问题,我们可以再设计一个中间件,在获取到用户的角色名时将其关于角色权限的ClaimTypes加入到 content.User 即可。关于这一方面的详细介绍和实现可以看下一篇文章。

本文介绍的相关代码已经提供 Nuget 包,并开源了代码,感兴趣的同学可以查阅:https://github.com/sangyuxiaowu/Sang.AspNetCore.RoleBasedAuthorization

如有错漏之处,敬请指正。

References

[1] Sang.AspNetCore.RoleBasedAuthorization: https://www.nuget.org/packages/Sang.AspNetCore.RoleBasedAuthorization [2] 《基于角色的授权》: https://learn.microsoft.com/zh-cn/aspnet/core/security/authorization/roles?view=aspnetcore-6.0 [3] 策略的授权: https://learn.microsoft.com/zh-cn/aspnet/core/security/authorization/policies?view=aspnetcore-6.0 [4] 使用 ASP.NET Core 中的应用程序模型: https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/application-model?view=aspnetcore-6.0 [5] 自定义授权策略提供程序: https://learn.microsoft.com/zh-cn/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-6.0 [6] 授权策略的处理: https://learn.microsoft.com/zh-cn/aspnet/core/security/authorization/policies?view=aspnetcore-6.0

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 桑榆肖物 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
IdentityServer4实战 - 基于角色的权限控制及Claim详解
一.前言 大家好,许久没有更新博客了,最近从重庆来到了成都,换了个工作环境,前面都比较忙没有什么时间,这次趁着清明假期有时间,又可以分享一些知识给大家。在QQ群里有许多人都问过IdentityServ
晓晨
2018/06/22
2.5K0
造轮子之自定义授权策略
前面我们已经弄好了用户角色这块内容,接下来就是我们的授权策略。在asp.net core中提供了自定义的授权策略方案,我们可以按照需求自定义我们的权限过滤。 这里我的想法是,不需要在每个Controller或者Action打上AuthorizeAttribute,自动根据ControllerName和ActionName匹配授权。只需要在Controller基类打上一个AuthorizeAttribute,其他Controller除了需要匿名访问的,使用统一的ControllerName和ActionName匹配授权方案。 话不多说,开整。
饭勺oO
2023/10/18
2360
造轮子之自定义授权策略
Asp.Net Core 中IdentityServer4 实战之角色授权详解
前几篇文章分享了IdentityServer4密码模式的基本授权及自定义授权等方式,最近由于改造一个网关服务,也用到了IdentityServer4的授权,改造过程中发现比较适合基于Role角色的授权,通过不同的角色来限制用户访问不同的Api资源,这里我就来分享IdentityServer4基于角色的授权详解。
Jlion
2022/04/07
5480
Asp.Net Core 中IdentityServer4 实战之角色授权详解
一文读懂 TKE 及 Kubernetes 访问权限控制
作者漆猛龙,腾讯云后台开发工程师, 腾讯云TKE的权限与安全模块、集群生命周期管理模块负责人。 你有了解过Kubernetes的认证授权链路吗?是否对TKE的权限控制CAM策略、服务角色傻傻分不清楚?本文将会向你介绍腾讯云TKE平台侧的访问控制、Kubernetes访问控制链路,以及演示如何将平台侧账号对接到Kubernetes内。 当你在使用腾讯云容器服务TKE(Tencent Kubernetes Engine)的时候,如果多人共用一个账号的情况下,是否有遇到以下问题呢? 密钥由多人共享,泄密风险高。
腾讯云原生
2021/01/21
1.9K0
ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露
  在涉及到后端项目的开发中,如何实现对于用户权限的管控是需要我们首先考虑的,在实际开发过程中,我们可能会运用一些已经成熟的解决方案帮助我们实现这一功能,而在 Grapefruit.VuCore 这个项目中,我将使用 Jwt 的方式实现对于用户的权限管控,在本章中,我将演示如何使用 Jwt 实现对于用户的授权、鉴权。
程序员宇说
2019/09/11
2.4K0
ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露
ASP.NET Core 2.2 : 二十七. JWT与用户授权(细化到Action)
上一章分享了如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新,本章继续进行下一步,用户授权。涉及到的例子也以上一章的为基础。(ASP.NET Core 系列目录)
FlyLolo
2019/09/04
1.6K0
通过中间件添加用户的Claim
前面我们介绍了通过对自定义授权策略和自定义授权处理程序的使用实现了基本的RBAC权限设计,将大量的用户可访问资源及操作的标识直接放到用户的 JWT Token 中显然并不合适,这篇文章我们主要介绍通过中间件如何根据用户的角色添加用户的 Claim。
桑榆肖物
2022/11/18
3580
使用RoleBasedAuthorization实现基于用户角色的访问权限控制
添加库 Sang.AspNetCore.RoleBasedAuthorization
桑榆肖物
2022/11/18
1.3K0
Gin集成Casbin进行访问权限控制
Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型,Casbin只负责访问控制[1]。
没有故事的陈师傅
2021/04/08
3.8K1
ASP.NET Core策略授权和 ABP 授权
Github 仓库源码地址 https://github.com/whuanles/2020-07-12
痴者工良
2021/04/26
2.3K0
.Net Core JWT 动态设置接口与权限,.Net Core官方的 JWT 授权验证
通过上一篇.Net Core官方的 JWT 授权验证学习到了JWT的授权。可以发现一个问题,就是如果每个接口可以使用的角色都是写死的,这样如果有所修改会非常麻烦,虽然用policy可以一定程度上缓解,但是还是不能根治。
huofo
2022/03/17
2.4K0
ASP.NET Core 使用 JWT 自定义角色/策略授权需要实现的接口
可以把授权访问的 API 存放到 Token 中,Token 也可以只存放角色信息和用户身份信息。
痴者工良
2021/04/26
2.7K0
Asp.net core IdentityServer4与传统基于角色的权限系统的集成
“我的公司有几百个接口,IdentityServer4能不能做到关联用户,给这些用户授予不同的接口的权限呢?”
乔达摩@嘿
2022/05/10
9700
Asp.net core IdentityServer4与传统基于角色的权限系统的集成
【 .NET Core 3.0 】框架之五 || JWT权限验证
这里一共三个文章,目前是第一篇,剩下两篇主要是在博客园,大家点击阅读原文,自行查看就行。
老张的哲学
2022/04/10
2.2K0
【 .NET Core 3.0 】框架之五 || JWT权限验证
.Net Core实战之基于角色的访问控制的设计
  上个月,我写了两篇微服务的文章:《.Net微服务实战之技术架构分层篇》与《.Net微服务实战之技术选型篇》,微服务系列原有三篇,当我憋第三篇的内容时候一直没有灵感,因此先打算放一放。
陈珙
2020/06/12
1.5K0
ASP.NET Core 6框架揭秘实例演示[40]:基于角色的授权
ASP.NET应用并没有对如何定义授权策略做硬性规定,所以我们完全根据用户具有的任意特性(如性别、年龄、学历、所在地区、宗教信仰、政治面貌等)来判断其是否具有获取目标资源或者执行目标操作的权限,但是针对角色的授权策略依然是最常用的。角色(或者用户组)实际上就是对一组权限集的描述,将一个用户添加到某个角色之中就是为了将对应的权限赋予该用户。在《使用最简洁的代码实现登录、认证和注销》中,我们提供了一个用来演示登录、认证和注销的程序,现在我们在此基础上添加基于“角色授权的部分”。(本文提供的示例演示已经同步到《ASP.NET Core 6框架揭秘-实例演示版》)
蒋金楠
2023/07/10
3100
ASP.NET Core 6框架揭秘实例演示[40]:基于角色的授权
实现一个登录:Mac+.NET 5+Identity+JWT+VS Code
.NET圈儿的朋友们,大家好!我可太喜欢如今开源的.Net了,写代码很巴适!所以今天分享一下之前学习的一个登录小案例,代码有不足之处欢迎指正!!!
郑子铭
2021/11/10
5420
实现一个登录:Mac+.NET 5+Identity+JWT+VS Code
ASP.NET Core Authentication and Authorization
最近把一个Asp .net core 2.0的项目迁移到Asp .net core 3.1,项目启动的时候直接报错:
MJ.Zhou
2020/04/08
1.1K0
ASP.NET Core Authentication and Authorization
asp.net core 认证及简单集群
众所周知,在Asp.net WebAPI中,认证是通过AuthenticationFilter过滤器实现的,我们通常的做法是自定义AuthenticationFilter,实现认证逻辑,认证通过,继续管道处理,认证失败,直接返回认证失败结果,类似如下:
guokun
2020/09/03
1.2K0
asp.net core 认证及简单集群
ASP.NET MVC 随想录—— 使用ASP.NET Identity实现基于声明的授权,高级篇
在这篇文章中,我将继续ASP.NET Identity 之旅,这也是ASP.NET Identity 三部曲的最后一篇。在本文中,将为大家介绍ASP.NET Identity 的高级功能,它支持声明式并且还可以灵活的与ASP.NET MVC 授权结合使用,同时,它还支持使用第三方来实现身份验证。 关于ASP.NET Identity 的基础知识,请参考如下文章: ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇 ASP.NET MVC 随想录——探索ASP.NET
用户1161731
2018/01/11
2.4K0
ASP.NET MVC 随想录——  使用ASP.NET Identity实现基于声明的授权,高级篇
推荐阅读
相关推荐
IdentityServer4实战 - 基于角色的权限控制及Claim详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文