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

.NET 8预渲染Blazor站点能否同时实现OpenId网页与JwtBearer API认证?

同时实现Blazor站点OIDC认证与API JWT认证的解决方案

问题背景

我们拥有一个采用ServerPrerendered模式的.NET 8 Blazor站点,网页需通过OpenIdConnectDefaults.AuthenticationScheme对接企业SSO,供已登录用户访问;目前新增了一个API控制器,其端点需使用JwtBearerDefaults.AuthenticationScheme,以便其他系统调用。

原Program.cs配置代码

var builder = WebApplication.CreateBuilder(args);

Workflow.Startup(builder.Configuration);

builder.Services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

builder.Services.AddSingleton(userController => new UserController())
                .AddSingleton(logController => new LoggingController())
                .AddSingleton(adminController => new AdminController())
                .AddSingleton(recordController => new RecordController())
                .AddSingleton(storageController => new StorageController())
                .AddSingleton(svfRecordController => new SvfRecordController());

builder.Services.AddHttpContextAccessor();

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("ApiAzureAd"));

builder.Services.AddControllersWithViews()
    .AddMicrosoftIdentityUI();

builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy
    options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services.AddRazorPages();

builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();
    
builder.Services.AddBlazorBootstrap();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

//this allows the IP Address of the caller to be obtained for logs, from here : https://stackoverflow.com/questions/28664686/how-do-i-get-client-ip-address-in-aspnet-core
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor |
    ForwardedHeaders.XForwardedProto
});

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
else
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

当前问题现象

  • 注释掉OpenIdConnectDefaults.AuthenticationScheme相关配置后,API可通过Postman正常调用,但网页全部返回401错误(未进入渲染逻辑)
  • 注释掉JwtBearerDefaults.AuthenticationScheme相关配置后,网页功能正常,但API无法接收请求

解决方案

核心问题

两次调用AddAuthentication会覆盖默认认证方案,导致只有最后配置的认证方式生效。需要同时注册两种认证方案,并为不同端点指定对应策略。

具体修改步骤

1. 合并认证服务配置

只调用一次AddAuthentication,设置默认方案为OIDC(适配Blazor网页),再添加JWT Bearer认证:

// 设置默认认证方案为OIDC,同时添加JWT Bearer认证
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("ApiAzureAd"), 
        jwtBearerScheme: JwtBearerDefaults.AuthenticationScheme);

2. 配置区分式授权策略

为API创建专属授权策略,指定使用JWT认证方案:

builder.Services.AddAuthorization(options =>
{
    // 默认策略:适配Blazor网页,使用OIDC认证
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    
    // API专属策略:强制使用JWT Bearer认证
    options.AddPolicy("ApiJwtPolicy", policy =>
    {
        policy.RequireAuthenticatedUser()
              .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
    });
    
    options.FallbackPolicy = options.DefaultPolicy;
});

3. 为API控制器绑定策略

在API控制器或Action上添加特性,指定使用API专属策略:

[ApiController]
[Route("api/[controller]")]
[Authorize(Policy = "ApiJwtPolicy")]
public class YourApiController : ControllerBase
{
    // 你的API接口实现
}

4. 调整MVC全局过滤器(可选)

原代码中给AddControllersWithViews添加的全局AuthorizeFilter会影响Microsoft Identity的UI页面,建议移除,改为在需要认证的控制器上单独添加[Authorize]:

builder.Services.AddControllersWithViews(options =>
{
    // 移除全局认证过滤器,避免干扰Identity UI
    // var policy = new AuthorizationPolicyBuilder()
    //     .RequireAuthenticatedUser()
    //     .Build();
    // options.Filters.Add(new AuthorizeFilter(policy));
    
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

验证效果

  • Blazor网页访问时自动触发OIDC企业SSO登录流程,正常渲染页面
  • API请求携带合法JWT Token时,通过ApiJwtPolicy验证,正常处理请求
  • 两种认证方式独立工作,互不冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:05:55