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

.NET 7 Web API:如何为AddJwtBearer的ISecurityTokenValidator注入依赖

解决方案

1. 修正自定义JWT验证器代码

先修复MyJwtSecurityTokenHandler中的错误实现,确保核心接口方法正常工作,并优化验证逻辑:

public class MyJwtSecurityTokenHandler : ISecurityTokenValidator
{
    private int _maxTokenSizeInBytes = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;
    private readonly JwtSecurityTokenHandler _tokenHandler;
    private readonly IServiceProvider _serviceProvider;

    public MyJwtSecurityTokenHandler(IServiceProvider serviceProvider)
    {
        _tokenHandler = new JwtSecurityTokenHandler();
        _serviceProvider = serviceProvider;
    }

    public int MaximumTokenSizeInBytes
    {
        get => _maxTokenSizeInBytes;
        set => _maxTokenSizeInBytes = value;
    }

    // 修正显式接口实现,返回true表示支持Token验证
    bool ISecurityTokenValidator.CanValidateToken => true;

    public bool CanReadToken(string securityToken)
    {
        return _tokenHandler.CanReadToken(securityToken);
    }

    public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
    {
        try
        {
            // 创建作用域获取业务服务
            using var scope = _serviceProvider.CreateScope();
            var authService = scope.ServiceProvider.GetRequiredService<IAuthService>();
            
            // 执行自定义验证逻辑
            var username = authService.GetUsername(securityToken);
            if (string.IsNullOrEmpty(username))
            {
                throw new SecurityTokenValidationException("Token验证失败:无法获取有效用户名");
            }

            // 调用默认JWT验证逻辑完成基础验证
            return _tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken);
        }
        catch (SecurityTokenValidationException)
        {
            // 直接抛出框架兼容的验证异常,交由认证中间件处理失败响应
            throw;
        }
        catch (Exception ex)
        {
            validatedToken = null;
            throw new SecurityTokenValidationException("Token验证出错", ex);
        }
    }
}

2. 注册自定义验证器到依赖注入容器

在Program.cs中,将自定义验证器注册为单例服务(符合JWT处理器的无状态生命周期特性):

// 注册自定义JWT验证器
builder.Services.AddSingleton<MyJwtSecurityTokenHandler>();
// 可选:同时注册为ISecurityTokenValidator接口,便于后续其他场景复用
builder.Services.AddSingleton<ISecurityTokenValidator>(sp => sp.GetRequiredService<MyJwtSecurityTokenHandler>());

3. 配置JWT Bearer时注入自定义验证器

使用PostConfigure延迟配置JWT选项(确保服务容器已完全构建,能正确解析依赖),替换默认Token验证器:

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = true;
    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("custom validation key")),
        ValidateIssuer = false,
        ValidateAudience = true,
    };
});

// 延迟注入自定义验证器,避免容器未构建完成导致的依赖解析失败
builder.Services.PostConfigure<JwtBearerOptions>((serviceProvider, options) =>
{
    var myTokenValidator = serviceProvider.GetRequiredService<MyJwtSecurityTokenHandler>();
    options.SecurityTokenValidators.Clear();
    options.SecurityTokenValidators.Add(myTokenValidator);
});

核心说明

  • 选择PostConfigure:在ConfigureServices阶段服务容器尚未完全初始化,直接获取服务可能失败;PostConfigure会在容器构建完成后执行,确保依赖解析正常。
  • 单例生命周期:JWT处理器无状态,单例模式更符合性能要求。
  • 抛出标准异常:用SecurityTokenValidationException替代返回null,让ASP.NET Core认证中间件自动返回401/403标准响应。

内容的提问来源于stack exchange,提问作者B.Balamanigandan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 16:30:46