.NET Core 6应用如何基于URL动态加载AzureAdB2C配置
动态加载Azure AD B2C配置(基于子域名)
我有一个基于.NET Core 6.0开发的应用,需求是根据访问的URL(例如不同子域名aaaa.test.com、bbbb.test.com等)动态加载对应的Azure AD B2C配置,且配置不存储在appsettings.json中,而是从SQL等数据源动态获取。
我已经找到基于appsettings.json配置多套Azure AD B2C参数的方案,但需要更灵活的动态加载方式,目前尝试多种方法均未成功,以下是我尝试过的代码片段:
builder.Services.AddAuthentication(options => { options.DefaultScheme = "TokenLogin"; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie("TokenLogin", options => { options.ExpireTimeSpan = DateTime.Now.Subtract(DateTime.UtcNow).Add(TimeSpan.FromDays(2)); options.Cookie.MaxAge = options.ExpireTimeSpan; options.SlidingExpiration = true; }) .AddMicrosoftIdentityWebApp(options => { builder.Configuration.Bind("AzureADB2C", options); //-------> 我尝试过的操作 //var xxx = builder.Services.BuildServiceProvider().GetService<IHttpContextAccessor>().HttpContext; //var authOptions = xxx.RequestServices.GetRequiredService<IOptionsMonitor<AzureADB2C>>(); ////var authOptions = xxx.RequestServices.GetRequiredService<AzureADB2C>(); //options.Instance = authOptions.CurrentValue.Instance; //options.ClientId = authOptions.CurrentValue.ClientId; //options.CallbackPath = authOptions.CurrentValue.CallbackPath; //options.Domain = authOptions.CurrentValue.Domain; //options.SignUpSignInPolicyId = authOptions.CurrentValue.SignUpSignInPolicyId; //options.ResetPasswordPolicyId = authOptions.CurrentValue.ResetPasswordPolicyId; //options.EditProfilePolicyId = authOptions.CurrentValue.EditProfilePolicyId; //options.SignInScheme = OpenIdConnectDefaults.AuthenticationScheme; //options.Events ??= new OpenIdConnectEvents(); //options.Events.OnRedirectToIdentityProvider += OnRedirectToIdentityProviderFunc; //options.Events.OnRedirectToIdentityProvider = context => //{ // Your code here //return Task.CompletedTask; //}; //options.Instance = authOptions.Instance; //options.ClientId = authOptions.ClientId; //options.CallbackPath = authOptions.CallbackPath; //options.Domain = authOptions.Domain; //options.SignUpSignInPolicyId = authOptions.SignUpSignInPolicyId; //options.ResetPasswordPolicyId = authOptions.ResetPasswordPolicyId; //options.EditProfilePolicyId = authOptions.EditProfilePolicyId; //authOptions.OnChange(newOptions => { // if (!settingsWereLoaded) // { // //options.Instance = authOptions.CurrentValue.Instance; // //options.ClientId = authOptions.CurrentValue.ClientId; // //options.Domain = authOptions.CurrentValue.Domain; // options.Instance = "https://xxxx.b2clogin.com/tfp/"; // options.ClientId = "XXXXX-XXXX-XXXX-XXXX-XXXX"; // options.Domain = "XXXX.onmicrosoft.com"; // settingsWereLoaded = true; // } //}); });
解决方案
1. 注册HttpContext访问服务
首先确保能在认证事件中获取当前请求信息,注册IHttpContextAccessor:
builder.Services.AddHttpContextAccessor();
2. 实现配置获取服务
创建从SQL读取子域名对应B2C配置的服务:
public interface IAdB2cConfigService { Task<AzureADB2COptions> GetConfigBySubdomain(string subdomain); } public class AdB2cConfigService : IAdB2cConfigService { private readonly YourDbContext _dbContext; public AdB2cConfigService(YourDbContext dbContext) { _dbContext = dbContext; } public async Task<AzureADB2COptions> GetConfigBySubdomain(string subdomain) { var config = await _dbContext.B2cConfigs .FirstOrDefaultAsync(c => c.Subdomain.Equals(subdomain, StringComparison.OrdinalIgnoreCase)); if (config == null) throw new InvalidOperationException($"未找到{subdomain}对应的B2C配置"); return new AzureADB2COptions { Instance = config.Instance, ClientId = config.ClientId, Domain = config.Domain, SignUpSignInPolicyId = config.SignUpSignInPolicyId, ResetPasswordPolicyId = config.ResetPasswordPolicyId, EditProfilePolicyId = config.EditProfilePolicyId, CallbackPath = "/signin-oidc" }; } }
注册该服务:
builder.Services.AddScoped<IAdB2cConfigService, AdB2cConfigService>();
3. 动态配置认证事件
在认证服务配置中,通过OnRedirectToIdentityProvider事件动态替换B2C参数:
builder.Services.AddAuthentication(options => { options.DefaultScheme = "TokenLogin"; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie("TokenLogin", options => { options.ExpireTimeSpan = TimeSpan.FromDays(2); // 简化原代码的时间计算逻辑 options.Cookie.MaxAge = options.ExpireTimeSpan; options.SlidingExpiration = true; }) .AddMicrosoftIdentityWebApp(options => { // 无需绑定静态配置,留空即可 }) .AddOpenIdConnect(options => { options.Events = new OpenIdConnectEvents { OnRedirectToIdentityProvider = async context => { // 解析当前请求的子域名 var hostParts = context.HttpContext.Request.Host.Host.Split('.'); var subdomain = hostParts.Length >= 2 ? hostParts[0] : string.Empty; // 获取对应配置 var configService = context.HttpContext.RequestServices.GetRequiredService<IAdB2cConfigService>(); var b2cConfig = await configService.GetConfigBySubdomain(subdomain); // 动态替换认证参数 context.ProtocolMessage.IssuerAddress = $"{b2cConfig.Instance}{b2cConfig.Domain}/{b2cConfig.SignUpSignInPolicyId}/v2.0/"; context.ProtocolMessage.ClientId = b2cConfig.ClientId; context.ProtocolMessage.RedirectUri = $"{context.HttpContext.Request.Scheme}://{context.HttpContext.Request.Host}{b2cConfig.CallbackPath}"; // 其他参数按需替换 context.ProtocolMessage.SetParameter("domain_hint", b2cConfig.Domain); } }; });
核心要点
- 服务注册阶段无法获取
HttpContext,必须在认证事件中动态处理请求信息 - 可给配置服务添加缓存逻辑(如分布式缓存),减少SQL查询次数
- 确保每个子域名的重定向URI已在Azure AD B2C应用中配置
内容的提问来源于stack exchange,提问作者Florin Paraschivescu
相关产品推荐
相关产品推荐

