ASP.NET Core 7 Web API如何为不同端点配置两种认证方式?
解决ASP.NET Core 7中同时配置Azure AD B2C和Basic Auth认证的问题
问题根源
你遇到的核心问题是混淆了**认证(Authentication)和授权(Authorization)**的职责:
- 仅实现授权处理程序(
AuthorizationHandler)不足以让Basic Auth成为有效的认证方式,Azure AD B2C的认证中间件会优先检查请求,没有AD令牌直接返回401。 - 添加
[AllowAnonymous]会跳过所有认证和授权校验,导致两种规则都失效。
解决方案
要为不同端点配置独立的认证方式,需要分别注册两种认证方案,并通过授权策略绑定到对应端点。
步骤1:实现Basic Auth认证处理程序
替换原有的授权处理程序,实现AuthenticationHandler来处理Basic Auth的身份验证:
public class BasicAuthOptions : AuthenticationSchemeOptions { public string Username { get; set; } public string Password { get; set; } } public class BasicAuthHandler : AuthenticationHandler<BasicAuthOptions> { public BasicAuthHandler(IOptionsMonitor<BasicAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } protected override Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.ContainsKey("Authorization")) return Task.FromResult(AuthenticateResult.NoResult()); try { var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); var credentialBytes = Convert.FromBase64String(authHeader.Parameter); var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':', 2); var username = credentials[0]; var password = credentials[1]; if (username.Equals(Options.Username, StringComparison.OrdinalIgnoreCase) && password.Equals(Options.Password)) { var claims = new[] { new Claim(ClaimTypes.Name, username) }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } return Task.FromResult(AuthenticateResult.Fail("Invalid username or password")); } catch { return Task.FromResult(AuthenticateResult.Fail("Invalid authorization header format")); } } }
步骤2:注册认证方案与授权策略
在Program.cs中同时注册Azure AD B2C和Basic Auth认证,并配置对应的授权策略:
var builder = WebApplication.CreateBuilder(args); // 添加控制器服务 builder.Services.AddControllers(); // 注册认证方案:Azure AD B2C + Basic Auth builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // Azure AD B2C配置(保留原有正常运行的配置) .AddJwtBearer(options => { options.Authority = "https://your-b2c-tenant.b2clogin.com/your-tenant-id/your-policy/v2.0"; options.Audience = "your-client-id"; // 其他Azure AD B2C相关配置... }) // Basic Auth配置 .AddScheme<BasicAuthOptions, BasicAuthHandler>("BasicAuth", options => { // 从appsettings.json读取配置 options.Username = builder.Configuration["BasicAuth:Username"]; options.Password = builder.Configuration["BasicAuth:Password"]; }); // 配置授权策略 builder.Services.AddAuthorization(options => { // 默认策略:使用Azure AD B2C认证 options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); // Basic Auth专属策略:指定使用BasicAuth认证方案 options.AddPolicy("BasicAuth", policy => policy.AddAuthenticationSchemes("BasicAuth") .RequireAuthenticatedUser()); }); var app = builder.Build(); // 启用认证与授权中间件(顺序不能错) app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
步骤3:为端点绑定对应策略
在控制器中,为不同端点指定对应的授权策略:
[ApiController] [Route("api/[controller]")] public class SampleController : ControllerBase { // 使用Azure AD B2C认证(默认策略) [Authorize] [HttpGet("ad-protected")] public IActionResult AdProtectedEndpoint() { return Ok("已通过Azure AD B2C认证"); } // 使用Basic Auth认证 [Authorize(Policy = "BasicAuth")] [HttpGet("basic-protected")] public IActionResult BasicProtectedEndpoint() { return Ok("已通过Basic Auth认证"); } }
可选:支持同时使用两种认证方式
如果需要某个端点允许用户选择Azure AD B2C或Basic Auth认证,可以添加多方案支持的策略:
builder.Services.AddAuthorization(options => { options.AddPolicy("AllowAdOrBasic", policy => policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme, "BasicAuth") .RequireAuthenticatedUser()); });
然后在端点上使用:
[Authorize(Policy = "AllowAdOrBasic")] [HttpGet("multi-auth")] public IActionResult MultiAuthEndpoint() { return Ok("已通过Azure AD B2C或Basic Auth认证"); }
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

