.NET5托管WebAssembly同时配置Azure AD与个人账号认证问题求助
问题1:externallogin页面404修复方案
问题原因与修复步骤:
- 错误的默认挑战方案配置:你当前把
DefaultChallengeScheme设为了OpenIdConnectDefaults.AuthenticationScheme,这会导致登录请求直接触发Azure AD OIDC挑战,跳过IdentityServer4的外部登录流程,回调后的路由和Identity默认的外部登录处理逻辑不匹配,触发404。
修复:移除AddAuthentication的sharedOptions配置,改为默认配置即可:
// 替换原有带sharedOptions的AddAuthentication配置 services.AddAuthentication() .AddOpenIdConnect("AAD", "Azure Active Directory", options => { options.ClientSecret = "<Secrete>"; options.ResponseType = OpenIdConnectResponseType.CodeIdToken; options.ClientId = "<ClientId>"; options.Authority = "https://login.microsoftonline.com/<tenantId>/"; // 建议改成自定义回调路径,避免和默认oidc回调冲突,需和Azure门户配置完全一致 options.CallbackPath = "/signin-aad"; options.SaveTokens = true; options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; }) .AddCookie() .AddIdentityServerJwt();
如果需要直接跳转AAD登录不需要展示登录方式选择页,可以在前端登录按钮的跳转地址中指定scheme参数:/Identity/Account/ExternalLogin?scheme=AAD&returnUrl=xxx即可。
- 缺失Razor Pages路由映射:Identity的外部登录相关页面是基于Razor Pages实现的,Blazor WASM托管模板默认可能没有开启Razor Pages路由,需要在
Configure方法的端点配置里添加映射:
app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); // 必须添加,负责Identity相关页面的路由解析 endpoints.MapControllers(); endpoints.MapBlazorHub(); endpoints.MapFallbackToFile("index.html"); });
如果使用自定义Identity UI没有采用默认脚手架页面,需要确保你已经手动实现了/Identity/Account/ExternalLogin对应的页面处理逻辑,否则也会触发404。
问题2:自动创建Azure AD对应本地用户实现
在AddOpenIdConnect的配置里添加Events配置,处理OnTicketReceived事件,在这个事件中获取Azure AD返回的用户信息,查询本地数据库,不存在则自动创建用户:
.AddOpenIdConnect("AAD", "Azure Active Directory", options => { // 原有配置保持不变,新增Events配置 options.Events = new OpenIdConnectEvents { OnTicketReceived = async context => { // 从返回的Claims中获取Azure AD用户唯一标识,优先取oid var oid = context.Principal.FindFirstValue("oid") ?? context.Principal.FindFirstValue(ClaimTypes.NameIdentifier); var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>(); // 查找本地是否存在关联的用户,可根据业务调整匹配字段 var user = await userManager.FindByLoginAsync("AAD", oid); if (user == null) { // 从Claims中提取用户基础信息 var email = context.Principal.FindFirstValue("preferred_username") ?? context.Principal.FindFirstValue(ClaimTypes.Email); var name = context.Principal.FindFirstValue("name") ?? email.Split('@')[0]; // 创建本地用户 user = new ApplicationUser { UserName = email, Email = email, DisplayName = name, // 根据你的ApplicationUser自定义字段调整 EmailConfirmed = true // Azure AD返回的邮箱默认已验证,可直接设为true }; var createResult = await userManager.CreateAsync(user); if (createResult.Succeeded) { // 关联外部登录信息到本地用户 await userManager.AddLoginAsync(user, new UserLoginInfo("AAD", oid, "Azure Active Directory")); // 如需默认分配角色可在此处添加 await userManager.AddToRoleAsync(user, "普通用户"); } else { // 处理创建失败逻辑 context.Fail("用户创建失败:" + string.Join(",", createResult.Errors.Select(e => e.Description))); return; } } // 可选:将本地用户的角色信息添加到Claims中 var roles = await userManager.GetRolesAsync(user); var appIdentity = new ClaimsIdentity(context.Principal.Identity); foreach (var role in roles) { appIdentity.AddClaim(new Claim(ClaimTypes.Role, role)); } context.Principal = new ClaimsPrincipal(appIdentity); } }; });
注意事项:
确保Azure AD的应用注册中已经开放了profile、email、openid三个API权限,否则无法正常获取对应的用户Claims。测试时请清除浏览器缓存,避免旧Cookie影响登录流程。
内容的提问来源于stack exchange,提问作者Javad Esfandiari
相关产品推荐
相关产品推荐

