.NET 5 Web API 同时集成Identity与Microsoft AD身份认证的方案咨询
.NET Core Web API 混合JWT与Microsoft AD身份验证实现方案
1. 服务端中间件配置
首先安装必要的NuGet包:
Microsoft.AspNetCore.Authentication.JwtBearer(你现有JWT验证已用到)Microsoft.AspNetCore.Authentication.MicrosoftAccount(Microsoft AD OAuth2验证支持)
然后在Program.cs中配置多身份验证方案:
builder.Services.AddAuthentication(options => { // 默认使用JWT作为身份验证方案 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { // 你原有JWT验证配置,保持不变 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; // 禁止未授权请求自动跳转登录页,适配API场景 options.Events = new JwtBearerEvents { OnChallenge = context => { context.HandleResponse(); context.Response.StatusCode = 401; return Task.CompletedTask; } }; }) .AddMicrosoftAccount(options => { // 从Azure AD应用注册页面获取以下参数 options.ClientId = builder.Configuration["AzureAd:ClientId"]; options.ClientSecret = builder.Configuration["AzureAd:ClientSecret"]; // 回调路径要和Azure AD中配置的重定向URI保持一致 options.CallbackPath = "/signin-microsoft"; // 可选:额外请求的权限范围 options.Scope.Add("user.read"); }); // 配置授权策略,支持两种验证方式 builder.Services.AddAuthorization(options => { options.AddPolicy("MixedAuth", policy => { policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme, MicrosoftAccountDefaults.AuthenticationScheme); policy.RequireAuthenticatedUser(); }); }); // 中间件注册顺序不要调整 app.UseAuthentication(); app.UseAuthorization();
需要受保护的控制器或接口直接标注[Authorize(Policy = "MixedAuth")]即可同时支持两种验证方式。
2. 前端对接与接口参数说明
前后端分离场景下,推荐采用以下流程对接Microsoft登录:
- 前端构造Microsoft OAuth2授权地址,引导用户跳转登录,授权地址可直接参考Azure AD规则拼接,也可请求后端的挑战接口自动生成跳转地址
- 用户在Microsoft登录页完成验证后,会自动跳转回你预先配置的回调地址,URL会携带
code(授权码)和可选的state参数 - 前端提取
code参数,传给后端的Microsoft登录接口即可
后端Microsoft登录接口仅需接收两个参数:
- 必填:
string code,Microsoft返回的授权码 - 可选:
string state,用于防跨站请求伪造校验
3. 控制器登录逻辑实现
Microsoft登录接口逻辑如下,完全复用你现有JWT签发和Identity用户操作逻辑:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { private readonly UserManager<IdentityUser> _userManager; private readonly IConfiguration _configuration; public AuthController(UserManager<IdentityUser> userManager, IConfiguration configuration) { _userManager = userManager; _configuration = configuration; } [HttpPost("microsoft-login")] public async Task<IActionResult> MicrosoftLogin([FromQuery] string code, [FromQuery] string? state = null) { // 用授权码向Microsoft换取用户身份信息 var authenticateResult = await HttpContext.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme); if (!authenticateResult.Succeeded) { return Unauthorized("Microsoft 身份验证失败"); } var claimsPrincipal = authenticateResult.Principal; // 获取Microsoft用户唯一标识与基础信息 var microsoftUserId = claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier); var userEmail = claimsPrincipal.FindFirstValue(ClaimTypes.Email); var userName = claimsPrincipal.FindFirstValue(ClaimTypes.Name); // 检查用户是否已存在于Identity体系中 var existingUser = await _userManager.FindByLoginAsync(MicrosoftAccountDefaults.AuthenticationScheme, microsoftUserId); if (existingUser == null) { // 首次登录,创建新Identity用户 existingUser = new IdentityUser { UserName = userName, Email = userEmail, EmailConfirmed = true }; var createResult = await _userManager.CreateAsync(existingUser); if (!createResult.Succeeded) { return BadRequest("用户创建失败"); } // 关联Microsoft登录信息到Identity用户 await _userManager.AddLoginAsync(existingUser, new UserLoginInfo( MicrosoftAccountDefaults.AuthenticationScheme, microsoftUserId, "Microsoft Account" )); } // 复用你现有JWT签发逻辑,生成令牌返回给前端 var jwtToken = GenerateJwtToken(existingUser); return Ok(new { Token = jwtToken }); } // 你原有JWT生成方法,保持不变 private string GenerateJwtToken(IdentityUser user) { // 原有逻辑实现 } // 你原有常规用户名密码登录接口,保持不变 [HttpPost("normal-login")] public async Task<IActionResult> NormalLogin([FromBody] LoginRequest request) { // 原有逻辑实现 } }
4. 注意事项
- Azure AD应用注册时,必须配置正确的重定向URI,与
AddMicrosoftAccount中配置的CallbackPath保持一致 - 两种登录方式最终返回的JWT格式完全一致,前端无需做额外适配
- 若需要限制AD登录的租户范围,可在
AddMicrosoftAccount配置中指定TenantId参数,避免外部租户用户登录
内容的提问来源于stack exchange,提问作者Praneet Nadkar
相关产品推荐
相关产品推荐

