ASP.NET Core 6 Cookie认证下多授权规则差异化重定向问题
1. 定义自定义授权需求类
创建两个需求类,明确区分角色权限缺失、订阅层级不足两种授权失败场景:
// 角色权限不足需求 public class RoleRequirement : IAuthorizationRequirement { public string RequiredRole { get; set; } public RoleRequirement(string role) => RequiredRole = role; } // 订阅层级不足需求 public class SubscriptionRequirement : IAuthorizationRequirement { public string RequiredTier { get; set; } public SubscriptionRequirement(string tier) => RequiredTier = tier; }
2. 实现自定义授权处理程序
分别编写处理程序验证用户Claims,验证失败时在授权上下文存储失败类型:
// 角色授权处理程序 public class RoleAuthorizationHandler : AuthorizationHandler<RoleRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement) { if (context.User.HasClaim(c => c.Type == ClaimTypes.Role && c.Value == requirement.RequiredRole)) { context.Succeed(requirement); } else { context.Items["AuthorizationFailureType"] = "RoleMissing"; context.Fail(); } return Task.CompletedTask; } } // 订阅授权处理程序 public class SubscriptionAuthorizationHandler : AuthorizationHandler<SubscriptionRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SubscriptionRequirement requirement) { // 假设订阅层级对应的ClaimType为"SubscriptionTier" var userTier = context.User.FindFirstValue("SubscriptionTier"); if (userTier == requirement.RequiredTier) { context.Succeed(requirement); } else { context.Items["AuthorizationFailureType"] = "SubscriptionMissing"; context.Fail(); } return Task.CompletedTask; } }
3. 注册授权服务与策略
在Program.cs中注册处理程序,并定义对应授权策略:
builder.Services.AddAuthorization(options => { // 管理员角色策略 options.AddPolicy("RequireAdminRole", policy => policy.Requirements.Add(new RoleRequirement("Admin"))); // 高级版订阅策略 options.AddPolicy("RequirePremiumSubscription", policy => policy.Requirements.Add(new SubscriptionRequirement("Premium"))); }); // 注册自定义授权处理程序 builder.Services.AddScoped<IAuthorizationHandler, RoleAuthorizationHandler>(); builder.Services.AddScoped<IAuthorizationHandler, SubscriptionAuthorizationHandler>();
4. 配置Cookie认证的差异化重定向事件
重写OnRedirectToAccessDenied事件,根据授权失败类型跳转对应页面:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/Login"; // 未认证用户跳转登录页 options.Events.OnRedirectToAccessDenied = context => { var authFailFeature = context.HttpContext.Features.Get<IAuthorizationFailureFeature>(); string failureType = null; if (authFailFeature?.Failure != null) { authFailFeature.Failure.Items.TryGetValue("AuthorizationFailureType", out var obj); failureType = obj as string; } // 根据失败类型分配跳转地址 string redirectUrl = failureType switch { "RoleMissing" => "/Account/RoleAccessDenied", "SubscriptionMissing" => "/Account/SubscriptionAccessDenied", _ => "/Account/AccessDenied" // 默认兜底页面 }; context.Response.Redirect(redirectUrl); return Task.CompletedTask; }; });
5. 配置UseEndpoints路由
ASP.NET Core 6中需使用UseEndpoints替代UseMvc,确保授权逻辑正常触发:
app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapRazorPages(); // 若使用Razor Pages需添加此配置 });
6. 控制器/页面中使用授权特性
在需要授权的控制器或动作上应用自定义策略:
// 需管理员角色的控制器 [Authorize(Policy = "RequireAdminRole")] public class AdminController : Controller { // 控制器逻辑 } // 需高级订阅的动作 [Authorize(Policy = "RequirePremiumSubscription")] public IActionResult PremiumExclusiveFeature() { return View(); }
补充说明
- 若需兼容原生
[Authorize(Roles = "Admin")]特性,建议统一替换为自定义策略,便于统一控制失败类型; - 确保用户Claims中已正确包含
Role和SubscriptionTier类型的声明; - 保留默认兜底页面,处理未定义的授权失败场景。
内容的提问来源于stack exchange,提问作者Medismal
相关产品推荐
相关产品推荐

