首页 > 其他分享 >造轮子之自定义授权策略

造轮子之自定义授权策略

时间:2023-10-09 17:25:26浏览次数:41  
标签:Wheel 自定义 Permission IPermissionChecker using 轮子 授权 public Authorization

前面我们已经弄好了用户角色这块内容,接下来就是我们的授权策略。在asp.net core中提供了自定义的授权策略方案,我们可以按照需求自定义我们的权限过滤。
这里我的想法是,不需要在每个Controller或者Action打上AuthorizeAttribute,自动根据ControllerName和ActionName匹配授权。只需要在Controller基类打上一个AuthorizeAttribute,其他Controller除了需要匿名访问的,使用统一的ControllerName和ActionName匹配授权方案。
话不多说,开整。

IPermissionChecker

首先我们需要一个PermissionChecker来作为检查当前操作是否有权限。很简单,只需要传入ControllerName和ActionName。至于实现,后续再写。

namespace Wheel.Authorization
{
    public interface IPermissionChecker
    {
        Task<bool> Check(string controller, string action);
    }
}

PermissionAuthorizationHandler

接下来我们则需要实现一个PermissionAuthorizationHandler和PermissionAuthorizationRequirement,继承AuthorizationHandler抽象泛型类。

using Microsoft.AspNetCore.Authorization;

namespace Wheel.Authorization
{
    public class PermissionAuthorizationRequirement : IAuthorizationRequirement
    {
        public PermissionAuthorizationRequirement()
        {
        }

    }
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Wheel.DependencyInjection;

namespace Wheel.Authorization
{
    public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>, ITransientDependency
    {
        private readonly IPermissionChecker _permissionChecker;

        public PermissionAuthorizationHandler(IPermissionChecker permissionChecker)
        {
            _permissionChecker = permissionChecker;
        }

        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)
        {
            if (context.Resource is HttpContext httpContext)
            {
                var actionDescriptor = httpContext.GetEndpoint()?.Metadata.GetMetadata<ControllerActionDescriptor>();
                var controllerName = actionDescriptor?.ControllerName;
                var actionName = actionDescriptor?.ActionName;
                if (await _permissionChecker.Check(controllerName, actionName))
                {
                    context.Succeed(requirement);
                }
            }
        }
    }
}

在PermissionAuthorizationHandler中注入IPermissionChecker。
然后通过重写HandleRequirementAsync进行授权策略的校验。
这里使用HttpContext获取请求的ControllerName和ActionName,再使用IPermissionChecker进行检查,如果通过则放行,不通过则自动走AspNetCore的其他AuthorizationHandler流程,不需要调用context.Fail方法。

PermissionAuthorizationPolicyProvider

这里除了AuthorizationHandler,还需要实现一个PermissionAuthorizationPolicyProvider,用于在匹配到我们自定义Permission的时候,就使用PermissionAuthorizationHandler做授权校验,否则不会生效。

using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Wheel.DependencyInjection;

namespace Wheel.Authorization
{
    public class PermissionAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider, ITransientDependency
    {
        public PermissionAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) : base(options)
        {
        }
        public override async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
        {
            var policy = await base.GetPolicyAsync(policyName);
            if (policy != null)
            {
                return policy;
            }
            if (policyName == "Permission")
            {
                var policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
                policyBuilder.AddRequirements(new PermissionAuthorizationRequirement());
                return policyBuilder.Build();
            }
            return null;
        }
    }
}

很简单,只需要匹配到policyName == "Permission"时,添加一个PermissionAuthorizationRequirement即可。

PermissionChecker

接下来我们来实现IPermissionChecker的接口。

namespace Wheel.Permission
{
    public class PermissionChecker : IPermissionChecker, ITransientDependency
    {
        private readonly ICurrentUser _currentUser;
        private readonly IDistributedCache _distributedCache;

        public PermissionChecker(ICurrentUser currentUser, IDistributedCache distributedCache)
        {
            _currentUser = currentUser;
            _distributedCache = distributedCache;
        }

        public async Task<bool> Check(string controller, string action)
        {
            if (_currentUser.IsInRoles("admin"))
                return true;
            foreach (var role in _currentUser.Roles)
            {
                var permissions = await _distributedCache.GetAsync<List<string>>($"Permission:R:{role}");
                if (permissions is null)
                    continue;
                if (permissions.Any(a => a == $"{controller}:{action}"))
                    return true;
            }
            return false;
        }
    }
}

通过当前请求用户ICurrentUser以及分布式缓存IDistributedCache做权限判断,避免频繁查询数据库。
这里ICurrentUser如何实现后续文章再写。
很简单,先判断用户角色是否是admin,如果是admin角色则默认所有权限放行。否则根据缓存中的角色权限进行判断。如果通过则放行,否则拒绝访问。

创建抽象Controller基类

创建WheelControllerBase抽象基类,添加[Authorize("Permission")]的特性头部,约定其余所有Controller都继承这个控制器。

    [Authorize("Permission")]
    public abstract class WheelControllerBase : ControllerBase
    {
        
    }

接下来我们测试一个需要权限的API。
image.png
image.png
image.png
image.png
通过DEBUG可以看到我们正常走了校验并响应401。

就这样我们完成了我们自定义的授权策略配置。

轮子仓库地址https://github.com/Wheel-Framework/Wheel
欢迎进群催更。

image.png

标签:Wheel,自定义,Permission,IPermissionChecker,using,轮子,授权,public,Authorization
From: https://www.cnblogs.com/fanshaoO/p/17752194.html

相关文章

  • 自定义滚动条 css
    /*自定义滚动条css*/.customScrollbar::-webkit-scrollbar{width:10px;height:10px;}.customScrollbar::-webkit-scrollbar-thumb{border-radius:8px;background-color:#47515b;}.customScrollbar::-webkit-scrollbar-thumb:hover{background-color:#5D626C;}.customScr......
  • css自定义滚动条
    .container{width:200px;height:150px;overflow:auto;/*自动显示滚动条/-ms-overflow-style:scrollbar;/在IE上显示自定义滚动条*/}/*自定义滚动条的样式*/.container::-webkit-scrollbar{width:10px;height:10px;}.container::-webkit-scrollbar-trac......
  • 造轮子之asp.net core identity
    在前面我们完成了应用最基础的功能支持以及数据库配置,接下来就是我们的用户角色登录等功能了,在asp.netcore中原生Identity可以让我们快速完成这个功能的开发,在.NET8中,asp.netcoreidentity支持了WebApi的注册登录。这让我们在WebApi中可以更爽快的使用。安装包首先我们需要安......
  • 【webapp】在 JSP 页面中引入标签库和使用自定义标签
    自定义标签的基本步骤:创建自定义标签库文件:首先,您需要创建一个包含自定义标签定义的标签库文件(通常以 .tld 扩展名结尾)。该文件描述了标签的名称、属性和处理逻辑。引入标签库:在JSP页面中,通过使用 <%@taglib%> 指令来引入自定义标签库。该指令告诉JSP引擎在页面中......
  • TinyMCE——自定义工具栏按钮(基础按钮、下拉框按钮、弹框按钮等)
    详细配置查看官方文档:https://www.tiny.cloud/docs/tinymce/6/custom-toolbarbuttons/  配置方式:tinymce.init({selector:'#editor',toolbar:'myCustomToolbarButton',setup:(editor)=>{editor.ui.registry.addButton('myCustomToolb......
  • PyQt 自定义信号带参数 emit
    PyQt5自定义信号带参数importsysfromPyQt5.QtCoreimportpyqtSignal,QObjectfromPyQt5.QtWidgetsimportQMainWindow,QApplicationclassmysignal(QObject):closeApp=pyqtSignal(list)classExample(QMainWindow):def__init__(self):super().......
  • 以实现资源池化弹性管理、企业应用集 中管理、统一安全认证和授权等管理
    使用提供的用户名密码,登录提供的OpenStack私有云平台,在当前租户下,使用CentOS7.9镜像,创建两台云主机,云主机类型使用4vCPU/12G/100G_50G类型。当前租户下默认存在一张网卡,自行创建第二张网卡并连接至controller和compute节点(第二张网卡的网段为192.168.X.0/24,X为工位......
  • vue封装搜索组件,自定义elment搜索组件
    组件案例<template><divclass="dialog-search"><el-form:inline="true"ref="ruleForm":model="formInline"class="demo-form-inlinetop-screen"><divclass="to......
  • 造轮子之ORM集成
    Dotnet的ORM千千万,还是喜欢用EFCORE前面一些基础完成的差不多了,接下来可以集成数据库了,官方出品的ORM还是比较香。所以接下来就是来集成EFCORE。安装包首先我们需要安装一下EFCORE的NUGET包,有如下几个:Microsoft.EntityFrameworkCore.ProxiesMicrosoft.EntityFrameworkC......
  • 造轮子之缓存
    缓存也是在业务开发过程中经常使用的一环。在Asp.netcore中,原生包含了MemoryCache内存缓存和DistributedCache分布式缓存两种缓存。在Program中添加以下代码注册服务之后即可使用依赖注入使用两种缓存。builder.Services.AddMemoryCache();varredis=awaitConnectionMultip......