根据this question,我使用下面的代码片段对JWToken
进行签名和加密。
var claims = new Claim[] { new SomeClaimes() };
var scKey = Encoding.UTF8.GetBytes("SOME KEY");
var ecKeyTemp = Encoding.UTF8.GetBytes("SOME OTHER KEY");
byte[] ecKey = new byte[256 / 8];
Array.Copy(ecKeyTemp, ecKey, 256 / 8);
var tokenDescriptor = new SecurityTokenDescriptor {
Subject = new ClaimsIdentity(claims),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(
scKey),
SecurityAlgorithms.HmacSha512),
EncryptingCredentials = new EncryptingCredentials(
new SymmetricSecurityKey(
ecKey),
SecurityAlgorithms.Aes256KW,
SecurityAlgorithms.Aes256CbcHmacSha512),
Issuer = "My Jwt Issuer",
Audience = "My Jwt Audience",
IssuedAt = DateTime.UtcNow,
Expires = DateTime.Now.AddDays(7),
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
var jwt = tokenHandler.WriteToken(token);
这是我的服务注册:
services
.AddAuthentication(o => {
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg => {
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters {
ValidIssuer = "My Jwt Issuer",
ValidAudience = "My Jwt Audience",
IssuerSigningKey = new SymmetricSecurityKey(SameKeyAsGenerating)),
TokenDecryptionKey = new SymmetricSecurityKey(SameKeyAsGenerating),
ClockSkew = TimeSpan.Zero,
RequireSignedTokens = true,
RequireExpirationTime = true,
SaveSigninToken = true,
ValidateActor = true,
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidateTokenReplay = true,
};
});
问题是身份验证层将授权的加密令牌和未加密令牌都进行身份验证。我的意思是,当我创建不带EncryptingCredentials
的令牌(只是签名令牌,未加密)时,该令牌仍然有效并且请求得到授权。问题是如何强制身份验证层仅接受经过签名的加密令牌,而拒绝刚刚签名的未加密令牌?
更新:解决方案:
由于sellotape's answer,我实现了JwtEncryptedSecurityTokenHandler
:
public class JwtEncryptedSecurityTokenHandler : JwtSecurityTokenHandler {
[DebuggerStepThrough]
public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken) {
if (string.IsNullOrWhiteSpace(token))
throw new ArgumentNullException(nameof (token));
if (validationParameters == null)
throw new ArgumentNullException(nameof (validationParameters));
if (token.Length > MaximumTokenSizeInBytes)
throw new ArgumentException(
$"IDX10209: token has length: '{token.Length}' which is larger than the MaximumTokenSizeInBytes: '{MaximumTokenSizeInBytes}'.");
var strArray = token.Split(new[] { '.' }, 6);
if (strArray.Length == 5)
return base.ValidateToken(token, validationParameters, out validatedToken);
throw new SecurityTokenDecryptionFailedException();
}
}
并在Startup.ConfigureServices()
中使用了新的处理程序:
.AddJwtBearer(cfg => {
cfg.RequireHttpsMetadata = false;
// other configurations...
cfg.SecurityTokenValidators.Clear();
cfg.SecurityTokenValidators.Add(new JwtEncryptedSecurityTokenHandler());
});
有关更多说明,请参见接受的答案。
答案 0 :(得分:1)
我敢肯定有几种方法可以做到这一点,但是如何做:
实现ISecurityTokenValidator
,可能继承自SecurityTokenHandler
;所需的覆盖非常简单,可以很大程度上从JwtSecurityTokenHandler
复制。覆盖ValidateToken()
并在JWT未加密的情况下抛出**。
在AddJwtBearer()
configure-options操作中添加新的处理程序/验证器:cfg.SecurityTokenValidators.Add(new RequireEncryptedTokenHandler());
**如果您查看source for JwtSecurityTokenHandler.ValidateToken()
(不确定所使用的版本,但我认为消息是相同的),似乎“已加密”被简单地确定为“具有5个部分” ”,那么在新处理程序中应该易于实现(复制/粘贴)。