JwtBearerAuthentication 安全处理异常

JwtBearerAuthentication Safe Handle Exception

使用JwtBearerAuthentication中间件时,调用JwtSecurityTokenHandler.WriteToken()后,RSACryptoServiceProvider等对象会被放置在SigningCredentials中。我的问题与这个问题非常相似:https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/477.

第一个请求有效,但任何后续请求都失败。此功能在 RC2 中运行良好...但现在我们已经升级到 1.0,WriteToken 结果为:

System.ObjectDisposedException was unhandled by user code HResult=-2146232798 Message=Safe handle has been closed ObjectName="" Source=mscorlib StackTrace: at System.Security.Cryptography.Utils._GetKeyParameter(SafeKeyHandle hKey, UInt32 paramID) at System.Security.Cryptography.RSACryptoServiceProvider.get_KeySize() at Microsoft.IdentityModel.Tokens.RsaSecurityKey.get_KeySize() at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.ValidateAsymmetricSecurityKeySize(SecurityKey key, String algorithm, Boolean willCreateSignatures) at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures) at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures) at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateEncodedSignature(String input, SigningCredentials signingCredentials) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token) at Api.Controllers.TokenController.CreateToken(EmployeeSecurityRecord record, DateTime expires) in C:\SOURCE\Api\Procede.Excede.Api.Core\src\Api\Controllers\TokenController.cs:line 115 at Api.Controllers.TokenController.Post(ResourceTokenRequest request) in C:\SOURCE\Api\Procede.Excede.Api.Core\src\Api\Controllers\TokenController.cs:line 35 at lambda_method(Closure , Object , Object[] ) at Microsoft.AspNetCore.Mvc.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionFilterAsync>d__28.MoveNext() InnerException:

我也找不到任何关于正确使用 JwtBearerAuthentication 的重要文档。有什么想法吗?这是我的实现...

在Startup.cs中:

配置服务:

        var keyFile = Configuration["AppSettings:Secret"];
        var keyParams = RSAKeyUtils.GetKeyParameters(Path.Combine(Environment.ContentRootPath, keyFile));

        var provider = new RSACryptoServiceProvider();
        provider.ImportParameters(keyParams);
        var key = new RsaSecurityKey(provider);

        _tokenOptions = new TokenAuthOptions
        {
            Audience = Configuration["AppSettings:Audience"],
            Issuer = Configuration["AppSettings:Issuer"],
            TokenLife = Convert.ToInt32(Configuration["AppSettings:TokenLife"]),
            Key = key,
            SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256Signature)
        };

配置:

        app.UseJwtBearerAuthentication(new JwtBearerOptions
        {
            TokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = _tokenOptions.Key,
                ValidAudience = _tokenOptions.Audience,
                ValidIssuer = _tokenOptions.Issuer,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromMinutes(1)
            }
        });

通过控制器方法创建令牌:

    private string CreateToken(EmployeeSecurityRecord record, DateTime expires)
    {
        var identity = new ClaimsIdentity(
            new GenericIdentity(record.EmpId, "TokenAuth"),
            new[]
            {
                new Claim("tid", "TBD", ClaimValueTypes.String),
                new Claim("branch_id", record.BrnId, ClaimValueTypes.String),
                new Claim("wid", record.WspId.ToString(), ClaimValueTypes.Integer),
                new Claim("roles", "TBD", ClaimValueTypes.String),
                new Claim("alt_sub", record.AltEmpId ?? "", ClaimValueTypes.String),
                new Claim("alt_wid", record.AltWspId == null ? "" : record.AltWspId.ToString(),
                    ClaimValueTypes.Integer),
                new Claim("alt_roles", "TBD", ClaimValueTypes.String)
            });

        var handler = new JwtSecurityTokenHandler();

        var descriptor = new SecurityTokenDescriptor
        {
            Issuer = _tokenOptions.Issuer,
            Audience = _tokenOptions.Audience,
            SigningCredentials = _tokenOptions.SigningCredentials,
            Subject = identity,
            Expires = expires
        };

        var token = handler.CreateToken(descriptor);

        return handler.WriteToken(token);

来自 Github 的 Microsoft 团队:

The library is disposing an rsa object it didn't create. A possible workaround it we get this fixed is based on JwtSecurityTokenHandler calling CryptoProviderFactory.ReleaseSignatureProvider after creating the signature. You can set your own CPF and override ReleaseSignatureProvider. RSP is in the call graph that will dispose the rsa. SigningCredentials. CryptoProviderFactory is a convenient place to set your CustomProviderFactory.

如果有时间我可能会尝试覆盖解决方案...否则,我将等待5.0.1版本发布。

GitHub Link