ASP.NET Core 6 JWT 不记名令牌异常

Jos*_*ado 0 c# google-authentication jwt bearer-token asp.net-core

我正在尝试使用 JWT 不记名令牌和谷歌身份验证来实现对 Web API 的身份验证。发现这个答案非常有帮助,但是当它成功验证时,我得到 500,但有以下例外:

System.NullReferenceException:未将对象引用设置为对象的实例。在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware:错误:执行请求时发生未处理的异常。

System.NullReferenceException:未将对象引用设置为对象的实例。在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() 在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() 在 Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync() 在 Microsoft.AspNetCore.Authentication.AuthenticationService .AuthenticateAsync(HttpContext 上下文,字符串方案) 在 Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 上下文) 在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)

当令牌无效时,我会收到 401 响应。

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
            {
                builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
            });
        });

        services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o =>
            {
                o.SecurityTokenValidators.Clear();
                o.SecurityTokenValidators.Add(
                    new GoogleTokenValidator(
                        client_id
                        ));
            });
        
        services.AddScoped<PhotoService>();
        services.AddScoped<TagService>();
        services.AddScoped(_ => new BlobServiceClient(Configuration.GetConnectionString("AzureBlobStorage")));
        services.AddDbContext<Data.DataContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddControllers().AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
        });
        services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "rvc", Version = "v1" }); });
    }

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            // app.UseSwagger();
            // app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "rvc v1"));
        }

        app.UseHttpsRedirection();

        if (env.IsProduction())
        {
            app.UseSpa(spa => { });

            app.UseFileServer(new FileServerOptions
            {
                FileProvider = new PhysicalFileProvider(
                    Path.Combine(env.ContentRootPath, "client")),
                EnableDefaultFiles = true
            });
        }

        app.UseRouting();
        app.UseCors();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
    }
Run Code Online (Sandbox Code Playgroud)

这是我的 GoogleTokenValidator:

 public class GoogleTokenValidator : ISecurityTokenValidator
{
    private readonly string _clientId;
    private readonly JwtSecurityTokenHandler _tokenHandler;

    public GoogleTokenValidator(string clientId)
    {
        _clientId = clientId;
        _tokenHandler = new JwtSecurityTokenHandler();
    }

    public bool CanValidateToken => true;

    public int MaximumTokenSizeInBytes { get; set; } = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;

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

    public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
    {
        validatedToken = null;
        try
        {
            validationParameters.ValidateIssuer = true;
            var payload = GoogleJsonWebSignature.ValidateAsync(securityToken, new GoogleJsonWebSignature.ValidationSettings() { Audience =  new[] { _clientId }}).Result; // here is where I delegate to Google to validate
        
            var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.NameIdentifier, payload.Name),
                    new Claim(ClaimTypes.Name, payload.Name),
                    new Claim(JwtRegisteredClaimNames.FamilyName, payload.FamilyName),
                    new Claim(JwtRegisteredClaimNames.GivenName, payload.GivenName),
                    new Claim(JwtRegisteredClaimNames.Email, payload.Email),
                    new Claim(JwtRegisteredClaimNames.Sub, payload.Subject),
                    new Claim(JwtRegisteredClaimNames.Iss, payload.Issuer),
                };

            var principle = new ClaimsPrincipal();
            principle.AddIdentity(new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme));
            return principle;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e);
            throw;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jos*_*ado 5

刚刚发现问题在于 validToken 为空。添加了这个并且它起作用了:

 (...)
 validatedToken = _tokenHandler.ReadJwtToken(securityToken); <-----
 var principle = new ClaimsPrincipal();
 (...)
Run Code Online (Sandbox Code Playgroud)