ASP.NET Core 8授权异常:未认证用户登录返回URL为Account/AccessDenied
问题
我有一个标记了[Authorize(Policy = "Staff")]的Razor页面,对应的授权策略配置如下:
options.AddPolicy("Staff", policy => { policy.RequireAuthenticatedUser(); policy.AddAuthenticationSchemes("MyAdSchemeName"); policy.RequireRole("Staff"); });
遇到两个问题:
- 未认证用户访问该页面时,虽会跳转到登录页,但跳转的查询参数里的返回URL是
Account/AccessDenied,不符合预期——应该先完成认证、获取角色后,再跳转回原页面判断权限。移除RequireRole配置后功能正常,但这样就无法限制用户角色。 - 应用中不存在
Account/AccessDenied页面,尝试配置AccessDeniedPath为/errors/403但没有效果。
相关的Program.cs代码如下:
var authentication = services.AddAuthentication(); authentication .AddMicrosoftIdentityWebApp( configuration.GetSection("AdConfig"), openIdConnectScheme: "MyAdSchemeName", cookieScheme: null, displayName: "MyAdSchemeName"); services.Configure<CookieAuthenticationOptions>("MyAdSchemeName", options => options.AccessDeniedPath = "/errors/403"); services.ConfigureApplicationCookie(options => { options.Events = new CookieAuthenticationEvents { OnRedirectToAccessDenied = context => { context.Response.StatusCode = 403; return Task.FromResult(0); } }; options.AccessDeniedPath = "/errors/403"; options.LoginPath = new PathString("/login"); }); services.AddAuthorization(options => { options.FallbackPolicy = options.DefaultPolicy; options.AddPolicy(PolicyNames.Staff, policy => { policy.RequireAuthenticatedUser(); policy.AddAuthenticationSchemes("MyAdSchemeName"); policy.RequireRole("Staff"); }); });
解决方案
1. 修复未认证用户跳转登录页的返回URL问题
问题根源是:授权策略同时要求认证和角色时,ASP.NET Core会优先判断角色,但此时用户未认证,直接触发权限拒绝逻辑,导致返回URL被设置为AccessDenied页面。
方案A:通过ClaimsTransformation动态添加角色
先创建一个Claims转换类,在用户认证完成后自动添加角色声明:
public class StaffClaimsTransformer : IClaimsTransformation { // 可注入用户服务、AD查询服务等用于判断角色 private readonly IHttpContextAccessor _httpContextAccessor; public StaffClaimsTransformer(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { // 替换为实际的角色判断逻辑,比如从AD或数据库查询用户是否属于Staff bool isStaff = /* 你的角色校验逻辑 */; if (isStaff && !principal.IsInRole("Staff")) { var identity = principal.Identity as ClaimsIdentity; identity.AddClaim(new Claim(ClaimTypes.Role, "Staff")); } return Task.FromResult(principal); } }
然后在Program.cs中注册这个转换类:
services.AddScoped<IClaimsTransformation, StaffClaimsTransformer>();
授权策略可以保留原配置,因为ClaimsTransformation会在认证完成后自动添加角色声明,此时RequireRole会正常校验:
options.AddPolicy(PolicyNames.Staff, policy => { policy.RequireAuthenticatedUser(); policy.AddAuthenticationSchemes("MyAdSchemeName"); policy.RequireRole("Staff"); });
方案B:用RequireAssertion控制逻辑顺序
显式指定先认证再检查角色的逻辑:
options.AddPolicy(PolicyNames.Staff, policy => { policy.RequireAuthenticatedUser(); policy.AddAuthenticationSchemes("MyAdSchemeName"); policy.RequireAssertion(context => { // 仅当用户已认证时才检查角色 return context.User.Identity.IsAuthenticated && context.User.IsInRole("Staff"); }); });
2. 修复AccessDeniedPath无效的问题
问题出在配置对象不匹配:你使用的是MyAdSchemeName认证方案,但配置的是ApplicationCookie的参数,同时OnRedirectToAccessDenied事件直接返回403状态码,覆盖了跳转逻辑。
正确配置步骤
- 调整
ConfigureApplicationCookie的事件逻辑(如果需要跳转而非仅返回403):
services.ConfigureApplicationCookie(options => { options.AccessDeniedPath = "/errors/403"; options.LoginPath = new PathString("/login"); // 如需自定义跳转,修改事件逻辑 options.Events.OnRedirectToAccessDenied = context => { context.Response.Redirect(options.AccessDeniedPath); return Task.CompletedTask; }; });
- 针对
MyAdSchemeName对应的Cookie方案配置(AddMicrosoftIdentityWebApp会自动生成Cookie方案,默认名称为Cookie+OpenID Connect方案名):
// 配置自动生成的Cookie方案 services.Configure<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.AccessDeniedPath = "/errors/403"; });
或者显式指定Cookie方案名称,再针对性配置:
const string cookieSchemeName = "MyAdCookieScheme"; authentication .AddMicrosoftIdentityWebApp( configuration.GetSection("AdConfig"), openIdConnectScheme: "MyAdSchemeName", cookieScheme: cookieSchemeName, displayName: "MyAdSchemeName"); // 配置指定的Cookie方案 services.Configure<CookieAuthenticationOptions>(cookieSchemeName, options => { options.AccessDeniedPath = "/errors/403"; options.LoginPath = "/login"; });
内容的提问来源于stack exchange,提问作者David Masters
相关产品推荐
相关产品推荐

