You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Microsoft Entra ID的.NET 8 Web应用Cookie转令牌认证方案咨询

.NET 8 Web应用从Entra ID Cookie认证迁移至令牌认证指引

一、核心逻辑说明

保留Entra ID的SSO跳转登录流程,改用授权码混合流获取ID令牌/访问令牌,前端将令牌存储在本地(如localStorage),后续请求通过Authorization: Bearer {token}请求头传递身份信息,后端用JWT Bearer方案验证令牌有效性,彻底避免使用Cookie存储用户身份。

二、步骤1:更新NuGet依赖

确保项目引用以下适配.NET 8的包:

  • Microsoft.Identity.Web
  • Microsoft.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应用注册配置

  1. 登录Azure门户,进入Microsoft Entra ID -> 应用注册 -> 目标应用
  2. 在证书和密码中生成客户端密码,将值填入appsettings.json的AzureAd:ClientSecret
  3. 在身份验证中:
    • 确保重定向URI包含配置的回调路径(如https://localhost:5001/signin-oidc)
    • 勾选ID令牌和访问令牌(混合流所需)
  4. 在API权限中添加所需权限(如Microsoft Graph > 委托权限 > User.Read),并完成管理员同意

五、步骤4:前端改造要点

  1. 触发登录:前端跳转至后端路由/MicrosoftIdentity/Account/SignIn,启动Entra ID SSO流程
  2. 存储令牌:登录成功后,从/auth/callback接口获取令牌,存入localStorage或sessionStorage
  3. 请求携带令牌:所有需认证的请求,添加请求头Authorization: Bearer {AccessToken}
  4. 登出处理:跳转至后端路由/MicrosoftIdentity/Account/SignOut,完成Entra ID登出后清除本地令牌

六、关键注意事项

  • 临时安全Cookie:流程中用到的Nonce/Correlation Cookie是Entra ID认证必需的临时校验Cookie,不存储用户身份,符合需求
  • 令牌续期:若添加了offline_access Scope,可通过刷新令牌实现令牌自动续期,避免用户频繁登录
  • 端点保护:所有需认证的接口/页面添加[Authorize]特性,默认使用JWT Bearer方案验证令牌
  • 自动验证:AddMicrosoftIdentityWebApi会自动验证令牌的签名、签发者、受众等合法性,无需手动实现

内容的提问来源于stack exchange,提问作者Master_T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:53:25