用路由动作名自动生成授权策略
接口一多,为每个按钮权限在启动时手写一长串 AddPolicy,策略表和控制器很快就会对不上。用路由动作名在运行时生成「同名声明」策略,能让策略名成为前后端共用的权限契约。
背景与问题
手写策略注册的痛点很具体:新增一个受保护动作,既要改控制器特性,又要改认证启动代码,还要在菜单和角色里配同名权限。漏一处就是 403,或接口根本没被保护。策略表膨胀后,没有人愿意做全量对照,线上往往靠点一下按钮看是否报错,才发现权限已经漂移。
策略名一旦散落在启动代码和控制器两处,重构动作名时很容易只改一边。运行时按名字匹配,拼写差一个字就会稳定地拒绝本该放行的请求。
做法
自定义 IAuthorizationPolicyProvider:当请求需要的策略名尚未手写注册时,动态生成一条「要求持有同名 policy 声明」的策略。策略名约定为路由键,例如 订单.提交,或控制器与动作的组合名。非 GET 请求还可以设默认策略,强制写操作必须带权限声明。
public sealed class RoutePolicyProvider : IAuthorizationPolicyProvider
{
private readonly DefaultAuthorizationPolicyProvider _fallback;
public RoutePolicyProvider(IOptions<AuthorizationOptions> options)
=> _fallback = new DefaultAuthorizationPolicyProvider(options);
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireClaim("policy", policyName)
.Build();
return Task.FromResult<AuthorizationPolicy?>(policy);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
=> _fallback.GetDefaultPolicyAsync();
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
=> _fallback.GetFallbackPolicyAsync();
}
登录成功时,遍历 MVC 的动作描述符,收集所有 [Authorize(Policy = ...)],把当前用户角色对应的策略写进令牌声明。超级管理员可以直接拥有全部已发现策略。
效果是:新增一个受保护动作,只要打上策略名特性,并在菜单和角色里配置同名权限,不必改认证中间件的注册表。
取舍与风险
策略名拼写不一致会导致接口要 订单.提交、令牌里只有 订单.提交 或大小写不同的变体。应用启动或登录时做一次策略清单对比,比运行时才发现 403 更省事。
动态生成也意味着任意字符串都可能成为策略名。写入令牌的声明应限制在已发现的动作策略之内,避免客户端自造声明。超级管理员的「全部策略」要随动作发现结果刷新,否则新接口会对超管也返回 403。
结语
用动作名自动生成同名声明策略,权限契约跟着路由走,启动时不必再维护一长串 AddPolicy。
本文介绍在C# ASP.NET Core中,利用控制器动作名自动生成同名声明式授权策略的方法。通过运行时动态注册策略,避免手动维护策略表与控制器特性不一致的问题,提升权限契约一致性与开发效率。方案支持令牌声明自动注入、超级管理员全权限刷新,并强调策略名拼写校验与安全边界控制。

296

被折叠的 条评论
为什么被折叠?



