在面向企业级 B2B SaaS 的开发中,身份认证(Authentication)远比简单的单租户登录复杂:
- 多租户混合上下文:同一个用户可能隶属于多个租户企业,登录后必须清晰界定当前激活的
TenantId; - 双通道认证:既要支持前端浏览器基于 JWT 的用户交互认证,又要支持第三方开放平台基于 API Key / HMAC 签名的机器间认证;
- 上下文篡改防范:严禁客户端在请求体中随意传递
UserId或TenantId来冒充身份!
BitzOrcas.Modern 建立了统一的身份解析底座:通过 ASP.NET Core Authentication 中间件解析凭据,并在请求作用域(Scoped)内自动注入不可变的 ICurrentUser 与 ICurrentTenant。
身份认证与安全上下文注入全景
第一步:从强类型上下文安全获取当前用户
在任何业务 Handler 中,严禁从 HTTP Body 或 Query 参数中读取 UserId。必须直接注入 ICurrentUser 与 ICurrentTenant:
using System;using System.Threading;using System.Threading.Tasks;using BitzOrcas.Application.Abstractions.Security;using BitzOrcas.Domain.Abstractions;using BitzOrcas.Domain.Results;
public static class AuthErrors{ public static readonly Error Unauthenticated = Error.Unauthorized("Auth.Unauthenticated", "请先登录后再进行操作。");}
public sealed class SubmitOrderCommandHandler( ICurrentUser currentUser, ICurrentTenant currentTenant, ICommandRepository<Order, string> orderRepository){ public async ValueTask<Result<string>> Handle(SubmitOrderCommand command, CancellationToken ct) { // 1. 从经由服务端签名验证的安全上下文中提取有效用户 ID 与租户 ID var userId = currentUser.UserId; var tenantId = currentTenant.Tenant.EffectiveTenantId;
// 2. 校验用户是否处于有效登录态 if (string.IsNullOrEmpty(userId)) { return Result<string>.Failure(AuthErrors.Unauthenticated); }
// 3. 执行业务持久化(自动注入真实的 UserId 与 TenantId) var order = Order.Create( id: Guid.NewGuid().ToString("N"), orderCode: command.OrderCode, totalAmount: command.TotalAmount, userId: userId, tenantId: tenantId).GetValueOrThrow();
var saveResult = await orderRepository.SaveAsync(order, ct); if (saveResult.IsFailure) { return Result<string>.Failure(saveResult.Error); }
return Result<string>.Success(order.Id); }}第二步:配置开放平台 API Key 认证通道
对于机器对机器(M2M)集成的 OpenAPI,通过注册 API Key 处理器实现高并发无状态验签:
using Microsoft.AspNetCore.Authentication;using Microsoft.Extensions.Options;
public sealed class ApiKeyAuthenticationHandler( IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, System.Text.Encodings.Web.UrlEncoder encoder, IApiKeyValidator apiKeyValidator) : AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder){ protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { // 1. 从请求头提取 X-API-Key if (!Request.Headers.TryGetValue("X-API-Key", out var apiKeyValue)) { return AuthenticateResult.NoResult(); }
// 2. 校验 API Key 的合法性与有效租户绑定 var validationResult = await apiKeyValidator.ValidateKeyAsync(apiKeyValue.ToString()); if (validationResult.IsFailure) { return AuthenticateResult.Fail("API Key 无效或已过期。"); }
// 3. 构造代表机器客户端的 ClaimsPrincipal 身份主体 var identity = validationResult.Value!; var ticket = new AuthenticationTicket(identity, Scheme.Name);
return AuthenticateResult.Success(ticket); }}总结
BitzOrcas 的身份认证体系兼顾安全性与易用性:
- 双通道统一:JWT 与 API Key 共享相同的下游授权上下文;
- 防越权防篡改:上下文完全由服务端在网关层签名构造;
- 多租户天然集成:自动解析有效租户,杜绝跨租户串号。