C# 如何加密 JWT 安全令牌?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18223868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:33:38  来源:igfitidea点击:

How to encrypt JWT security token?

c#securitywifjwt

提问by Qué Padre

I need to secure my web-token with signing and encryption. I wrote the next lines of code:

我需要通过签名和加密来保护我的网络令牌。我写了下几行代码:

var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
      Subject = new ClaimsIdentity(new[]
         {
             new Claim(ClaimTypes.Name, owner.Name),
             new Claim(ClaimTypes.Role, owner.RoleClaimType),
             new Claim("custom claim type", "custom content")
         }),
      TokenIssuerName = "self",
      AppliesToAddress = "http://www.example.com",
      Lifetime = new Lifetime(now, now.AddSeconds(60 * 3)),
      EncryptingCredentials = new X509EncryptingCredentials(new X509Certificate2(cert)),
      SigningCredentials = new X509SigningCredentials(cert1)
};
var token = (JwtSecurityToken)tokenHandler.CreateToken(tokenDescriptor);            
var tokenString = tokenHandler.WriteToken(token);

So, I am using some certificates, generated with makecert.exe. Then I read token string with another JwtSecurityTokenHandler:

所以,我正在使用一些证书,生成的makecert.exe. 然后我用另一个读取令牌字符串JwtSecurityTokenHandler

var tokenHandlerDecr = new JwtSecurityTokenHandler();
var tok = tokenHandlerDecr.ReadToken(tokenString);

And token content is not encrypted (I can see json in tokvariable under debugger). What am I doing wrong? How to encrypt token data?

并且令牌内容未加密(我可以tok在调试器下的变量中看到 json )。我究竟做错了什么?如何加密令牌数据?

采纳答案by Brock Allen

My understanding is that Microsoft's JWT implementation doesn't currently support encryption (only signing).

我的理解是微软的 JWT 实现目前不支持加密(仅签名)。

回答by Amey

I know this an old post, but I am adding my answer in case if someone is still searching for the answer.

我知道这是一篇旧帖子,但如果有人仍在寻找答案,我会添加我的答案。

This issue is addressed in Microsoft.IdentityModel.Tokensversion 5.1.3. There is an overloaded method available in the CreateJwtSecurityTokenfunction which accepts the encrypting credentials to encrypt the token.

此问题已在Microsoft.IdentityModel.Tokens5.1.3 版中解决。CreateJwtSecurityToken函数中有一个可用的重载方法,它接受加密凭据来加密令牌。

If the receiver does not validate the signature and tries to read JWT as is then the claims are empty. Following is the code snippet:

如果接收方未验证签名并尝试按原样读取 JWT,则声明为空。以下是代码片段:

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

const string sec = "ProEMLh5e_qnzdNUQrqdHPgp";
const string sec1 = "ProEMLh5e_qnzdNU";
var securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec));
var securityKey1 = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec1)); 

var signingCredentials = new SigningCredentials(
    securityKey,
    SecurityAlgorithms.HmacSha512);

List<Claim> claims = new List<Claim>()
{
    new Claim("sub", "test"),
};

var ep = new EncryptingCredentials(
    securityKey1,
    SecurityAlgorithms.Aes128KW,
    SecurityAlgorithms.Aes128CbcHmacSha256);

var handler = new JwtSecurityTokenHandler();

var jwtSecurityToken = handler.CreateJwtSecurityToken(
    "issuer",
    "Audience",
    new ClaimsIdentity(claims),
    DateTime.Now,
    DateTime.Now.AddHours(1),
    DateTime.Now,
    signingCredentials,
    ep);


string tokenString = handler.WriteToken(jwtSecurityToken);

// Id someone tries to view the JWT without validating/decrypting the token,
// then no claims are retrieved and the token is safe guarded.
var jwt = new JwtSecurityToken(tokenString);

And here is the code to validate/decrypt the token:

这是验证/解密令牌的代码:

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

const string sec = "ProEMLh5e_qnzdNUQrqdHPgp";
const string sec1 = "ProEMLh5e_qnzdNU";
var securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec));
var securityKey1 = new SymmetricSecurityKey(Encoding.Default.GetBytes(sec1));

// This is the input JWT which we want to validate.
string tokenString = string.Empty;

// If we retrieve the token without decrypting the claims, we won't get any claims
// DO not use this jwt variable
var jwt = new JwtSecurityToken(tokenString);

// Verification
var tokenValidationParameters = new TokenValidationParameters()
{
    ValidAudiences = new string[]
    {
        "536481524875-glk7nibpj1q9c4184d4n3gittrt8q3mn.apps.googleusercontent.com"
    },
    ValidIssuers = new string[]
    {
        "https://accounts.google.com"
    },
    IssuerSigningKey = securityKey,
    // This is the decryption key
    TokenDecryptionKey = securityKey1
};

SecurityToken validatedToken;
var handler = new JwtSecurityTokenHandler();

handler.ValidateToken(tokenString, tokenValidationParameters, out validatedToken);

回答by Hung Quach

Try the following example

试试下面的例子

Updated Jul-2019: .NET Core, Asp.net Core

2019 年 7 月更新:.NET Core、Asp.net Core

1.Create JWT

1.创建JWT

private string CreateJwt(string sub, string jti, string issuer, string audience)
{
    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, sub),
        new Claim(JwtRegisteredClaimNames.Jti, jti),
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SecretKeySecretKeySecretKeySecretKeySecretKeySecretKeySecretKeyS"));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    var encryptingCredentials = new EncryptingCredentials(key, JwtConstants.DirectKeyUseAlg, SecurityAlgorithms.Aes256CbcHmacSha512);

    var jwtSecurityToken = new JwtSecurityTokenHandler().CreateJwtSecurityToken(
        issuer,
        audience,
        new ClaimsIdentity(claims),
        null,
        expires: DateTime.UtcNow.AddMinutes(5),
        null,
        signingCredentials: creds,
        encryptingCredentials: encryptingCredentials
        );
    var encryptedJWT = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

    return encryptedJWT;
}

2.Add to ConfigureServices(IServiceCollection services)in Startup.cs

2.添加到ConfigureServices(IServiceCollection services)Startup.cs

    services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,

        ValidIssuer = (string)Configuration.GetSection("JwtToken").GetValue(typeof(string), "Issuer"),
        ValidAudience = (string)Configuration.GetSection("JwtToken").GetValue(typeof(string), "Audience"),
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SecretKeySecretKeySecretKeySecretKeySecretKeySecretKeySecretKeyS")),
        TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SecretKeySecretKeySecretKeySecretKeySecretKeySecretKeySecretKeyS")),
        ClockSkew = TimeSpan.FromMinutes(0),
    };
});