.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
相关产品推荐
相关产品推荐

