基于Microsoft Entra ID的.NET 8 Web应用Cookie转令牌认证方案咨询
一、核心逻辑说明
保留Entra ID的SSO跳转登录流程,改用授权码混合流获取ID令牌/访问令牌,前端将令牌存储在本地(如localStorage),后续请求通过Authorization: Bearer {token}请求头传递身份信息,后端用JWT Bearer方案验证令牌有效性,彻底避免使用Cookie存储用户身份。
二、步骤1:更新NuGet依赖
确保项目引用以下适配.NET 8的包:
Microsoft.Identity.WebMicrosoft.Identity.Web.UI
三、步骤2:修改Program.cs认证配置
替换原有Cookie认证代码,改为如下配置:
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Identity.Web; var builder = WebApplication.CreateBuilder(args); var azAdSettings = builder.Configuration.GetSection("AzureAd"); // 1. 配置JWT Bearer为默认认证方案(验证前端传入的令牌) builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration) .EnableTokenAcquisitionToCallDownstreamApi() .AddInMemoryTokenCaches(); // 2. 添加OpenID Connect认证(触发Entra ID SSO跳转) builder.Services.AddAuthentication() .AddMicrosoftIdentityWebApp(options => { // 复用原有Entra ID配置 options.Instance = azAdSettings["Instance"]; options.Domain = azAdSettings["Domain"]; options.TenantId = azAdSettings["TenantId"]; options.ClientId = azAdSettings["ClientId"]; options.ClientSecret = azAdSettings["ClientSecret"]; // 需在Entra ID应用注册中生成客户端密码 options.CallbackPath = azAdSettings["CallbackPath"]; options.SignedOutCallbackPath = azAdSettings["SignedOutCallbackPath"]; // 保留原有的临时安全Cookie配置(流程必需,不存储用户身份) options.NonceCookie.Name = "myAppNonceCookieName"; options.NonceCookie.SameSite = SameSiteMode.None; options.CorrelationCookie.Name = "myAppCorrelationCookieName"; options.CorrelationCookie.SameSite = SameSiteMode.None; // 配置令牌获取规则 options.ResponseType = "code id_token"; options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("User.Read"); options.Scope.Add("offline_access"); // 可选:获取刷新令牌用于续期 // 临时将令牌存入HttpContext,供回调路由读取 options.SaveTokens = true; options.UseTokenLifetime = true; // 自定义事件,确保令牌能被读取 options.Events = new OpenIdConnectEvents { OnTokenValidated = context => { context.HttpContext.Items["IdToken"] = context.SecurityToken.RawData; context.HttpContext.Items["AccessToken"] = context.TokenEndpointResponse.AccessToken; context.HttpContext.Items["RefreshToken"] = context.TokenEndpointResponse.RefreshToken; return Task.CompletedTask; } }; }); // 3. 配置默认授权策略 builder.Services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); }); // 添加Identity UI提供登录/登出路由 builder.Services.AddRazorPages().AddMicrosoftIdentityUI(); var app = builder.Build(); // 中间件配置 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // 自定义回调路由:返回令牌给前端 app.MapGet("/auth/callback", async (HttpContext context) => { if (context.Items.TryGetValue("IdToken", out var idToken) && context.Items.TryGetValue("AccessToken", out var accessToken)) { return Results.Json(new { IdToken = idToken.ToString(), AccessToken = accessToken.ToString(), RefreshToken = context.Items["RefreshToken"]?.ToString(), ExpiresAt = DateTime.UtcNow.AddSeconds(int.Parse(context.GetTokenAsync("expires_in").Result)) }); } return Results.BadRequest("Failed to retrieve authentication tokens"); }).AllowAnonymous(); app.MapRazorPages(); app.MapControllers(); app.Run();
四、步骤3:调整Entra ID应用注册配置
- 登录Azure门户,进入Microsoft Entra ID -> 应用注册 -> 目标应用
- 在证书和密码中生成客户端密码,将值填入
appsettings.json的AzureAd:ClientSecret - 在身份验证中:
- 确保重定向URI包含配置的回调路径(如
https://localhost:5001/signin-oidc) - 勾选ID令牌和访问令牌(混合流所需)
- 确保重定向URI包含配置的回调路径(如
- 在API权限中添加所需权限(如
Microsoft Graph > 委托权限 > User.Read),并完成管理员同意
五、步骤4:前端改造要点
- 触发登录:前端跳转至后端路由
/MicrosoftIdentity/Account/SignIn,启动Entra ID SSO流程 - 存储令牌:登录成功后,从
/auth/callback接口获取令牌,存入localStorage或sessionStorage - 请求携带令牌:所有需认证的请求,添加请求头
Authorization: Bearer {AccessToken} - 登出处理:跳转至后端路由
/MicrosoftIdentity/Account/SignOut,完成Entra ID登出后清除本地令牌
六、关键注意事项
- 临时安全Cookie:流程中用到的Nonce/Correlation Cookie是Entra ID认证必需的临时校验Cookie,不存储用户身份,符合需求
- 令牌续期:若添加了
offline_accessScope,可通过刷新令牌实现令牌自动续期,避免用户频繁登录 - 端点保护:所有需认证的接口/页面添加
[Authorize]特性,默认使用JWT Bearer方案验证令牌 - 自动验证:
AddMicrosoftIdentityWebApi会自动验证令牌的签名、签发者、受众等合法性,无需手动实现
内容的提问来源于stack exchange,提问作者Master_T
相关产品推荐
相关产品推荐

