前言
知识点:
ASP.NET Core 中的筛选器
目的: 利用 Filter 自定义权限过滤到按钮级别
1 简单介绍
通过使用 ASP.NET Core 中的筛选器,可在请求处理管道中的特定阶段之前或之后运行代码。
总共有五种类型的筛选器,分别在筛选器管道中的不同阶段执行:
-
授权筛选器
最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,授权筛选器可以让管道短路。 资源筛选器
- 授权后运行。
-
OnResourceExecuting
在筛选器管道的其余阶段之前运行代码。 -
OnResourceExecuted
在管道的其余阶段完成之后运行代码。
操作筛选器
- 在调用操作方法之前和之后立即运行代码。
- 可以更改传递到操作中的参数。
- 可以更改从操作返回的结果。
- 不可在 Razor Pages 中使用。
异常筛选器
- 在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。
结果筛选器
- 在执行操作结果之前和之后立即运行代码。 仅当操作方法成功执行时,它们才会运行。 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。
过滤器执行顺序图: 当然 Filter
是在 Endpoint
终结点中间件 里面执行的
2 编写自定义权限过滤器
其实Filter都一样,只是他们的执行顺序不同,同时,在同一类型下的过滤器也可以通过 Order
进行排序。
所以统一采用了 ActionFilter
进行处理,利用 Order
排序执行。
2.1 创建 Filter
实现Filter很简单,只需要实现 IAsyncActionFilter
,即可以在 before
和 after
中随心所欲的穿插代码。
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 扩展
同理可得,通过 Attribute
和 Filter
可以灵活扩展,AOP思想实践,例如无缝刷新Token机制,以及数据库事物一致机制均可实现!
3 大功告成!