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

.NET Minimal APIs如何实现API密钥全局校验避免重复验证代码

解决方案

你可以通过以下三种常用方式实现API-KEY校验逻辑复用,避免每个接口重复编写代码:


方案1:端点过滤器(推荐,.NET 7及以上版本适用)

这是Minimal API原生提供的扩展能力,支持单接口或批量接口统一挂载逻辑:

  1. 首先定义校验过滤器
public class ApiKeyValidationFilter : IEndpointFilter
{
    // 注入你的ApiKey校验服务、数据库上下文等依赖
    private readonly IApiKeyValidationService _validationService;

    public ApiKeyValidationFilter(IApiKeyValidationService validationService)
    {
        _validationService = validationService;
    }

    public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
    {
        // 直接从当前请求上下文获取API-KEY头
        if (!context.HttpContext.Request.Headers.TryGetValue("API-KEY", out var apiToken) 
            || string.IsNullOrWhiteSpace(apiToken))
        {
            return Results.Unauthorized();
        }

        // 执行你的校验逻辑:比对数据库值、判断过期时间等
        if (!_validationService.Validate(apiToken))
        {
            return Results.Unauthorized();
        }

        // 校验通过则继续执行接口业务逻辑
        return await next(context);
    }
}
  1. 给需要校验的接口挂载过滤器即可
// 单个接口单独挂载
app.MapGet("/getCustomers", () =>
{
    // 无需再写校验逻辑,直接写业务代码
    return Database.Customers.ToList();
}).AddEndpointFilter<ApiKeyValidationFilter>();

// 批量接口统一挂载:用路由组统一配置,组下所有接口自动带校验
var needAuthApiGroup = app.MapGroup("/api")
                          .AddEndpointFilter<ApiKeyValidationFilter>();
needAuthApiGroup.MapGet("/getCustomers", () => Database.Customers.ToList());
needAuthApiGroup.MapPost("/addCustomer", (Customer customer) => { /* 业务逻辑 */ });

方案2:自定义授权策略(全.NET版本适用)

基于ASP.NET Core原生授权体系实现,兼容性最强:

  1. 定义ApiKey认证处理器
public class ApiKeyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly IApiKeyValidationService _validationService;

    public ApiKeyAuthenticationHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock,
        IApiKeyValidationService validationService) 
        : base(options, logger, encoder, clock)
    {
        _validationService = validationService;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.TryGetValue("API-KEY", out var apiToken) || string.IsNullOrWhiteSpace(apiToken))
        {
            return AuthenticateResult.Fail("缺失API-KEY请求头");
        }

        if (!_validationService.Validate(apiToken))
        {
            return AuthenticateResult.Fail("无效的API-KEY");
        }

        // 校验通过后可将用户信息存入Claims,后续接口中可直接读取
        var claims = new[] { new Claim(ClaimTypes.Name, "ApiUser") };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);

        return AuthenticateResult.Success(ticket);
    }
}
  1. 注册服务与中间件
// Program.cs 中注册服务
builder.Services.AddScoped<IApiKeyValidationService, ApiKeyValidationService>();
builder.Services.AddAuthentication("ApiKey")
    .AddScheme<AuthenticationSchemeOptions, ApiKeyAuthenticationHandler>("ApiKey", _ => { });
builder.Services.AddAuthorization();

// 中间件管道添加配置,注意顺序要放在路由之后、端点之前
app.UseAuthentication();
app.UseAuthorization();
  1. 给需要校验的接口开启授权即可
// 单个接口开启授权
app.MapGet("/getCustomers", [Authorize] () =>
{
    return Database.Customers.ToList();
});

// 路由组统一开启授权
var needAuthApiGroup = app.MapGroup("/api").RequireAuthorization();
needAuthApiGroup.MapGet("/getCustomers", () => Database.Customers.ToList());

方案3:自定义注入类实现(符合你最初的思路)

如果你希望用自己定义的RequiresApiTokenKey类实现,只需要注入IHttpContextAccessor即可获取当前请求上下文:

  1. 注册HttpContext访问器
builder.Services.AddHttpContextAccessor();
  1. 改造你的自定义类
public class RequiresApiTokenKey
{
    public bool IsValid { get; }
    public RequiresApiTokenKey(IHttpContextAccessor httpContextAccessor, IApiKeyValidationService validationService)
    {
        var httpContext = httpContextAccessor.HttpContext;
        if (httpContext == null)
        {
            IsValid = false;
            return;
        }
        if (!httpContext.Request.Headers.TryGetValue("API-KEY", out var apiToken) || string.IsNullOrWhiteSpace(apiToken))
        {
            IsValid = false;
            return;
        }
        IsValid = validationService.Validate(apiToken);
    }
}
  1. 注册自定义类后即可在接口中注入使用
// 注册服务
builder.Services.AddTransient<RequiresApiTokenKey>();

// 接口中直接注入使用
app.MapGet("/getCustomers", (RequiresApiTokenKey apiKeyChecker) =>
{
    if (!apiKeyChecker.IsValid) return Results.Unauthorized();
    return Database.Customers.ToList();
});

该方案仍需在每个接口中添加有效性判断,复用性不如前两种方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 03:15:02