前言

知识点:
ASP.NET Core 中的筛选器 目的: 利用 Filter 自定义权限过滤到按钮级别

1 简单介绍

通过使用 ASP.NET Core 中的筛选器,可在请求处理管道中的特定阶段之前或之后运行代码。
总共有五种类型的筛选器,分别在筛选器管道中的不同阶段执行:

  • 授权筛选器 最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,授权筛选器可以让管道短路。
  • 资源筛选器
  • 授权后运行。
  • OnResourceExecuting 在筛选器管道的其余阶段之前运行代码。
  • OnResourceExecuted 在管道的其余阶段完成之后运行代码。
  • 操作筛选器
  • 在调用操作方法之前和之后立即运行代码。
  • 可以更改传递到操作中的参数。
  • 可以更改从操作返回的结果。
  • 不可在 Razor Pages 中使用。
  • 异常筛选器
  • 在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。
  • 结果筛选器
  • 在执行操作结果之前和之后立即运行代码。 仅当操作方法成功执行时,它们才会运行。 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。

过滤器执行顺序图: 当然 Filter 是在 Endpoint 终结点中间件 里面执行的

android 11 manifest权限被过滤了 filter权限过滤_执行顺序

2 编写自定义权限过滤器

其实Filter都一样,只是他们的执行顺序不同,同时,在同一类型下的过滤器也可以通过 Order 进行排序。
所以统一采用了 ActionFilter 进行处理,利用 Order 排序执行。

2.1 创建 Filter

实现Filter很简单,只需要实现 IAsyncActionFilter,即可以在 beforeafter 中随心所欲的穿插代码。

public class AuthFilter : IAsyncActionFilter
{
    public AuthFilter()
    {
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        //before
        await next();
        //after
    }
}

2.2 如何让方法做到不同的权限访问呢 ?

easy!在 await next(); 之前,进行权限的判断,如果没有权限则直接终止方法,返回无权限访问。
目标是通过 用户 角色 方法 共同决定 是否可以访问该方法,那么可以做到用户绑定角色,角色绑定方法。那怎么确定哪些方法需要做到权限的特殊控制呢?
此处,引入 Attribute 概念,特性就是为了给方法加上一个 标签 ,打上该标签的方法即为我们需要进行权限的特殊处理的方法。
故而,在 OnActionExecutionAsync 中的 context 可以获取到请求上下文,从而通过判断 用户 角色 方法 关系链,决定是否访问。关键代码如下:

/// <summary>
/// 自定义授权
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class X23AuthorizeAttribute : Attribute
{
    /// <summary>
    /// 自定义授权
    /// </summary>
    /// <param name="controllerName">控制器名称</param>
    /// <param name="permissions">权限列表</param>
    public X23AuthorizeAttribute(string controllerName, params string[] permissions)
    {
        ControllerName = controllerName;
        if (permissions.Length == 0)
        {
            throw new Exception($"请添加具体权限!controllerName={controllerName},permissionsLength={permissions.Length}");
        }
        PermissionList = permissions.ToList();
    }
    /// <summary>
    /// 控制器名称
    /// </summary>
    public string ControllerName { get; set; }
    /// <summary>
    /// 权限列表
    /// </summary>
    public List<string> PermissionList { get; set; }
}

......

/// <summary>
/// 测试权限查询
/// </summary>
/// <returns></returns>
[HttpGet]
[X23Authorize(nameof(TestController), ButtonConst.Query)]
public async Task<bool> TestAuthByQueryData()
{
    return await Task.FromResult(true);
}
/// <summary>
/// 判断用户是否有按钮权限
/// </summary>
/// <param name="context">ActionFilter上下文</param>
/// <param name="userId">用户Id</param>
/// <returns></returns>
private async Task<bool> IsPermission(ActionExecutingContext context,int userId)
{
    var isPermission = true;
    var actionDescriptor = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;
    var x23AuthorizeAttribute = actionDescriptor.MethodInfo.GetCustomAttributes(typeof(X23AuthorizeAttribute), false).FirstOrDefault();
    if (x23AuthorizeAttribute != null)
    {
        var x23Attribute = x23AuthorizeAttribute as X23AuthorizeAttribute;
        var x23PermissionList = x23Attribute.PermissionList;
        var x23ControllerName = x23Attribute.ControllerName;
        var roleList = await _roleManagementService.GetUserPermissionWithCache(userId);
        isPermission = roleList.Where(x => x.ControllerName == x23ControllerName && x23PermissionList.Contains(x.ButtonCode)).Count() =
 x23PermissionList.Count;
    }
    return await Task.FromResult(isPermission);
}

2.3 扩展

同理可得,通过 AttributeFilter 可以灵活扩展,AOP思想实践,例如无缝刷新Token机制,以及数据库事物一致机制均可实现!

3 大功告成!