问题
When using the JwtBearerAuthentication middleware, The RSACryptoServiceProvider and other objects are disposed in the SigningCredentials after JwtSecurityTokenHandler.WriteToken() is called. My issue is very similiar to this issue: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/477.
The first request works, but any subsequent requests fail. This functionality worked great in RC2... but now that we've upgrade to 1.0, WriteToken results in:
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:
I can't find any great documentation on proper usage of the JwtBearerAuthentication either. Any thoughts? Here is my implementation...
In Startup.cs:
ConfigureServices:
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)
};
Configure:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = _tokenOptions.Key,
ValidAudience = _tokenOptions.Audience,
ValidIssuer = _tokenOptions.Issuer,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(1)
}
});
Creating the token via a controller method:
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);
回答1:
From the Microsoft team on Github:
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.
I may try the override solution if I have time...otherwise, I'll wait for the 5.0.1 version to be release.
GitHub Link
来源:https://stackoverflow.com/questions/39401277/jwtbearerauthentication-safe-handle-exception