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

Blazor基于Entra MFA登录的会话时长设置问题

解决Blazor Entra MFA会话超时问题

你遇到的1小时强制登出是Azure AD默认的令牌过期机制导致的——当前你用的是JwtBearer无状态认证方案,代码里配置的ApplicationCookie和Session完全不会影响JWT的有效期,因为JWT的过期时间由令牌本身的exp字段决定,默认就是1小时。

核心解决步骤

1. 调整Azure AD应用的Token过期时间

直接在Entra ID控制台修改应用注册的令牌有效期:

  • 进入Entra ID → 应用注册 → 找到你的Blazor应用
  • 切换到「令牌配置」页面
  • 点击「添加配置」,分别设置访问令牌和ID令牌的过期时间(最长可设为24小时)
  • 保存后,新生成的Token就会使用这个有效期

2. 配置自动滑动刷新(实现长期会话)

如果需要超过24小时的会话,或者希望用户活跃时自动续期,需要开启Microsoft Identity Web的滑动刷新功能:
在AddMicrosoftIdentityWebApi之后添加JWT事件配置:

builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.Events = new JwtBearerEvents
    {
        OnTokenValidated = context =>
        {
            var expiresAt = context.SecurityToken.ValidTo;
            // 当Token剩余有效期不足30分钟时触发刷新
            if (expiresAt - DateTime.UtcNow < TimeSpan.FromMinutes(30))
            {
                var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
                // 替换成你的实际API权限范围
                tokenAcquisition.GetAccessTokenForUserAsync(new[] { "https://graph.microsoft.com/User.Read" })
                    .ContinueWith(task =>
                    {
                        if (task.IsCompletedSuccessfully)
                        {
                            context.Properties.UpdateTokenValue("access_token", task.Result);
                        }
                    });
            }
            return Task.CompletedTask;
        }
    };
});

同时要确保你的应用注册已添加offline_access权限,这样才能获取刷新令牌用于续期。

3. 清理无效配置

删除代码中对JWT认证无意义的配置,避免混淆:

  • 移除builder.Services.ConfigureApplicationCookie(...)
  • 移除builder.Services.AddSession(...)和builder.Services.AddMvc().AddSessionStateTempDataProvider()
  • 补充遗漏的app.UseAuthentication()中间件(原代码未添加,会导致认证逻辑不生效)

修改后的完整Program.cs示例

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// 配置Entra认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi()
            .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
            .AddDistributedTokenCaches()
            .AddSessionTokenCaches();

// 配置JWT滑动刷新
builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.Events = new JwtBearerEvents
    {
        OnTokenValidated = context =>
        {
            var expiresAt = context.SecurityToken.ValidTo;
            if (expiresAt - DateTime.UtcNow < TimeSpan.FromMinutes(30))
            {
                var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
                tokenAcquisition.GetAccessTokenForUserAsync(new[] { "https://graph.microsoft.com/User.Read" })
                    .ContinueWith(task =>
                    {
                        if (task.IsCompletedSuccessfully)
                        {
                            context.Properties.UpdateTokenValue("access_token", task.Result);
                        }
                    });
            }
            return Task.CompletedTask;
        }
    };
});

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

builder.Services.AddControllers().AddNewtonsoftJson(x => 
    x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

builder.Services.AddDbContext<DB>(x =>
    x.UseSqlServer(builder.Configuration.GetConnectionString("DB"))
    .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

var app = builder.Build();

// 管道配置
if (app.Environment.IsDevelopment()) {
    app.UseWebAssemblyDebugging();
} else {
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication(); // 必须添加的认证中间件
app.UseAuthorization();

app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 01:37:28