You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何强制ASP.NET Core认证提前运行,供限流中间件获取主体信息?

解决JWT验证提前执行,让限流中间件获取Claims的问题

这个问题我之前帮人排查过,核心就是JWT Bearer中间件的“被动触发”特性在搞鬼——你说得完全对,它默认只在请求碰到[Authorize]标记时才会去解析令牌、填充Context.User,所以你的限流中间件要么跑在验证逻辑之前,要么请求没触发授权,自然拿不到Claims。下面给你两种靠谱的解决方案:

方案一:全局强制令牌验证(适合全API都需要认证的场景)

如果你的所有API接口都要求携带有效JWT令牌,那直接全局开启认证验证是最简单的方式:

  1. ConfigureServices里给控制器添加全局授权过滤器,强制所有请求都经过认证:
services.AddControllers(options =>
{
    // 构建要求用户已认证的授权策略
    var authPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    // 把策略添加为全局过滤器
    options.Filters.Add(new AuthorizeFilter(authPolicy));
});
  1. 调整中间件注册顺序,确保认证、授权中间件先执行,再注册你的限流中间件:
// 先注册认证中间件,负责解析验证JWT
app.UseAuthentication();
// 再注册授权中间件,处理权限逻辑
app.UseAuthorization();

// 最后注册你的限流中间件,此时Context.User已经被填充
app.UseRateLimitingMiddleware();

这样一来,所有请求都会先经过JWT验证,你的限流中间件就能稳稳拿到Context.User.Claims里的客户端ID了。

方案二:手动触发令牌验证(适合部分接口无需认证的场景)

如果你的API有公开接口,但你希望限流中间件在这些接口里也能拿到客户端ID(只要请求带了有效令牌),可以在限流中间件里手动触发认证逻辑:

  1. 在你的限流中间件类里,注入IAuthenticationService(ASP.NET Core默认已经注册了这个服务):
public class RateLimitingMiddleware
{
    private readonly RequestDelegate _next;

    public RateLimitingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, IAuthenticationService authService)
    {
        // 手动触发JWT Bearer认证
        var authResult = await authService.AuthenticateAsync(context, JwtBearerDefaults.AuthenticationScheme);
        
        if (authResult.Succeeded)
        {
            // 认证成功后,把用户主体设置到Context.User
            context.User = authResult.Principal;
        }

        // 继续执行后续管道中的中间件
        await _next(context);
    }
}
  1. 同样要注意中间件顺序,把限流中间件注册在UseAuthentication()之后(虽然是手动触发,但遵循管道顺序更稳妥)。

额外提示

不管用哪种方案,记得从Claims里取**client_id**这个Claim值——Identity Server 4颁发的JWT里,客户端ID对应的Claim类型就是这个,你可以用这段代码获取:

var clientId = context.User.FindFirst("client_id")?.Value;

内容的提问来源于stack exchange,提问作者Hugo Quintela Ribeiro

火山引擎 最新活动