Blazor Server集成AAD登录后无限重定向至AccessDenied问题排查
我开发了一个集成Azure Active Directory(AAD)登录的Blazor Server应用,希望基于用户角色限制仅特定用户可访问。
现有代码
Program.cs
builder.Services .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection(AppConsts.Config.AzureAdSectionKey)) builder.Services.AddAuthorization(options => { options.FallbackPolicy = options.DefaultPolicy; }); builder.Services .AddControllersWithViews() .AddMicrosoftIdentityUI(); builder.Services.AddRazorPages(); app.UseAuthentication(); app.UseAuthorization(); //app.MapRazorPages(); 注释此行后,会出现无限重定向至MicrosoftIdentity/Account/AccessDenied?ReturnUrl=%2FMicrosoftIdentity%2FAccount%2FAccessDenied%3FReturnUrl% app.MapControllers(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .RequireAuthorization();
ClaimsTransformation实现
public class ClaimsTransformation : IClaimsTransformation { public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { if (!IsUserAllowed(principal)) { var emptyClaimIdentity = new ClaimsIdentity(); emptyClaimIdentity.AddClaim(new Claim(ClaimTypes.Name, principal.Identity?.Name ?? "anonym")); return new ClaimsPrincipal(emptyClaimIdentity); } return principal; } }
问题现象
注释app.MapRazorPages()后,应用会陷入无限重定向至MicrosoftIdentity/Account/AccessDenied的循环;添加该行代码后,则能正常显示“Access denied”页面。
疑问解答
1. 为何会出现重定向至AccessDenied页面的情况?
当IsUserAllowed返回false时,你返回的ClaimsPrincipal没有经过认证的身份标识——创建ClaimsIdentity时未传入认证类型参数,导致IsAuthenticated默认是false。
你的Blazor组件路由设置了.RequireAuthorization(),且授权FallbackPolicy沿用了默认策略(要求用户必须经过认证)。未认证用户访问受保护资源时,系统会触发权限校验失败,重定向到AccessDenied页面。
但注释app.MapRazorPages()后,MicrosoftIdentity/Account/AccessDenied这个路径没有对应的处理端点,请求会再次被Blazor的授权策略拦截,最终导致无限循环重定向。添加app.MapRazorPages()后,MicrosoftIdentityUI提供的Razor Pages端点被正确映射,请求能正常到达权限拒绝页面,循环终止。
2. MicrosoftIdentityUI包是否依赖Razor Pages?我原以为已切换为Controllers实现。
MicrosoftIdentityUI包默认基于Razor Pages实现,它提供的登录、登出、权限拒绝等页面都是Razor Pages组件。你调用.AddControllersWithViews()只是添加了MVC控制器支持,并没有替换MicrosoftIdentityUI的底层实现——它仍然需要Razor Pages的路由映射才能正常工作。
如果想完全使用控制器而非Razor Pages,需要自行实现权限拒绝、登录回调等对应的控制器动作,不能依赖MicrosoftIdentityUI提供的默认页面。
内容的提问来源于stack exchange,提问作者Liero

