如何通过OpenIdConnect集成Asp.Net Identity与Azure AD授权并实现切换?
当然可以实现!你完全可以在ASP.NET Core中同时集成Identity本地授权和Azure AD的OpenID Connect授权,下面我会一步步帮你调整现有配置,让两种方式都能正常工作且支持自由切换。
步骤1:添加ASP.NET Core Identity服务
首先,你需要在ConfigureServices方法中注册Identity服务——这是开启本地账号密码授权的基础。如果你用Entity Framework Core做数据存储,代码大致如下:
// 添加Identity服务(如果用自定义用户/角色类型,替换成你自己的类型即可) services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
注意:
AddDefaultIdentity会自动注册Cookie认证,使用的方案是IdentityConstants.ApplicationScheme,我们后续的认证配置需要兼容这个设定。
步骤2:调整认证配置
你现有的Azure AD OIDC配置大部分是正确的,但我们需要更新认证选项,让它同时支持两种授权方案,并且不要把默认挑战方案固定为Azure AD(这样用户才能自主选择登录方式)。修改后的配置如下:
_services.AddAuthentication(options => { // 将默认认证方案设为Cookie认证(同时兼容Identity本地登录和Azure AD登录) options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; // 不要设置默认挑战方案——让用户自主选择用哪种方式登录 // options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) // 保留你原有的Azure AD OIDC配置,但确保SignInScheme使用Cookie方案 .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.ClientId = clientId; options.ClientSecret = clientSecret; options.Authority = $"{baseAuthorityUrl}/{tenantId}/v2.0"; options.CallbackPath = new PathString(callBackPath); options.Scope.Add("email"); options.Scope.Add("profile"); options.ResponseType = "code id_token"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name" }; // 可选功能:将Azure AD用户关联到本地Identity账号(如果不存在则自动创建) options.Events = new OpenIdConnectEvents { OnTokenValidated = async context => { var email = context.Principal.FindFirstValue(ClaimTypes.Email); if (!string.IsNullOrEmpty(email)) { var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>(); var user = await userManager.FindByEmailAsync(email); if (user == null) { // 创建一个与Azure AD账号绑定的本地用户 user = new IdentityUser { UserName = email, Email = email }; await userManager.CreateAsync(user); } // 让本地Identity账号也完成登录,保持身份一致性 await context.HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, await userManager.CreateUserPrincipalAsync(user)); } await Task.CompletedTask; } }; }) // 显式添加Cookie认证方案(虽然Identity可能已经自动添加,但这样配置更清晰) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
步骤3:更新登录UI,提供两种登录选项
你需要修改登录页面(如果用Identity脚手架生成的话,通常是Login.cshtml),添加Azure AD登录的入口。
首先,在AccountController中添加一个触发Azure AD认证挑战的Action:
public IActionResult LoginWithAzureAd(string returnUrl = null) { var redirectUrl = Url.Action("Index", "Home", new { returnUrl }); return Challenge( new AuthenticationProperties { RedirectUri = redirectUrl }, OpenIdConnectDefaults.AuthenticationScheme); }
然后在Login.cshtml中添加Azure AD登录的按钮/表单,和本地登录表单并列:
<div class="row"> <div class="col-md-4"> <section> <h4>本地账号登录</h4> <hr /> <!-- 这里保留你原有的本地登录表单 --> </section> </div> <div class="col-md-4"> <section> <h4>使用Azure AD登录</h4> <hr /> <form asp-action="LoginWithAzureAd" asp-route-returnUrl="@Model.ReturnUrl" method="post"> <button type="submit" class="btn btn-primary">使用Azure AD登录</button> </form> </section> </div> </div>
步骤4:验证两种授权方式的兼容性
[Authorize]特性会对两种方式登录的用户生效,因为它们都使用了默认的Cookie认证方案。如果你需要限制某个页面只能用特定方式登录,可以指定认证方案:
// 仅允许Azure AD登录的用户访问 [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] public IActionResult AzureAdOnlyPage() { return View(); } // 仅允许本地Identity账号登录的用户访问 [Authorize(AuthenticationSchemes = IdentityConstants.ApplicationScheme)] public IActionResult LocalOnlyPage() { return View(); }
排查小技巧
- 如果你还没有生成过Identity的UI页面,可以运行
dotnet aspnet-codegenerator identity命令来生成本地登录所需的表单和页面。 - 检查Azure AD应用注册中的重定向URI,确保和你配置的
CallbackPath完全一致。 - 如果遇到Cookie相关问题,确保Cookie名称保持一致(或者让默认配置自动处理即可)。
内容的提问来源于stack exchange,提问作者Kipup fs
相关产品推荐
相关产品推荐

