Razor Pages中AddAuthorization实现HR部门授权策略失败排查
问题诊断与解决方案
你的核心问题在于重复创建认证会话,且自定义声明所在的会话未被授权中间件读取,具体分析和修复方案如下:
问题根源
你在登录逻辑中先调用了_signInManager.PasswordSignInAsync(使用Identity默认的Identity.Application认证Scheme创建会话),随后又手动调用HttpContext.SignInAsync("MyCookieAuth", claimsPrincipal)创建了另一个独立的认证会话。而ASP.NET Core的授权中间件默认只会读取默认认证Scheme对应的Claims,因此你手动添加的Department声明并没有被授权策略识别到。
修复方案
方案1:直接使用自定义认证会话(无需Identity用户系统额外功能)
移除SignInManager的登录调用,自行完成用户名密码验证后,直接创建包含自定义声明的认证会话:
修改Login页面的OnPostAsync方法:
public async Task<IActionResult> OnPostAsync(User user) { // 自行实现用户名密码验证逻辑(比如从数据库校验) bool isValidCredentials = /* 替换为你的验证逻辑,例如检查用户名密码是否匹配 */; if (isValidCredentials) { _logger.LogInformation("User logged in."); var claims = new List<Claim> { new Claim(ClaimTypes.Name, "admin"), new Claim(ClaimTypes.Email, "admin@mywebsite.com"), new Claim("Department", "HR") }; var identity = new ClaimsIdentity(claims, "MyCookieAuth"); ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(identity); await HttpContext.SignInAsync("MyCookieAuth", claimsPrincipal); return RedirectToPage("contact"); } else { return Page(); } }
同时在Program.cs中添加对应Cookie认证的配置(确保在授权配置之前):
// 配置Cookie认证 builder.Services.AddAuthentication("MyCookieAuth") .AddCookie("MyCookieAuth", options => { options.LoginPath = "/Login"; // 指定登录页面路径 }); // 原有的授权和Razor Pages配置保持不变 builder.Services.AddAuthorization(options => { options.AddPolicy("MustBelongToHRDepartment", policy => policy.RequireClaim("Department", "HR")); }); builder.Services.AddRazorPages(options => { options.Conventions.AuthorizePage("/contact", "MustBelongToHRDepartment"); });
方案2:将自定义声明添加到Identity用户体系(需保留Identity功能)
如果需要继续使用Identity的用户管理功能,不要手动创建新的认证会话,而是将自定义声明添加到已登录的用户身份中:
修改Login页面的OnPostAsync方法:
public async Task<IActionResult> OnPostAsync(User user) { var result = await _signInManager.PasswordSignInAsync(user.username, user.password, user.rememberMe, lockoutOnFailure: true); if (result.Succeeded) { _logger.LogInformation("User logged in."); // 获取当前登录的用户实体 var currentUser = await _userManager.FindByNameAsync(user.username); if (currentUser != null) { // 检查用户是否已存在该声明,避免重复添加 var existingClaim = await _userManager.GetClaimsAsync(currentUser) .FirstOrDefault(c => c.Type == "Department" && c.Value == "HR"); if (existingClaim == null) { await _userManager.AddClaimAsync(currentUser, new Claim("Department", "HR")); } // 刷新登录会话,使新声明生效 await _signInManager.RefreshSignInAsync(currentUser); } return RedirectToPage("contact"); } else { return Page(); } }
关键注意事项
确保在Program.cs的中间件管道中,认证中间件在授权中间件之前注册:
var app = builder.Build(); // ...其他中间件(如静态文件、路由等) app.UseAuthentication(); // 必须在UseAuthorization之前 app.UseAuthorization(); app.MapRazorPages(); app.Run();
内容的提问来源于stack exchange,提问作者Kaden Gaines
相关产品推荐
相关产品推荐

