【问题标题】:Net Core JWT Signing CredentialsNet Core JWT 签名凭证
【发布时间】:2018-07-26 04:20:53
【问题描述】:

我正在学习本教程: https://jonhilton.net/2017/10/11/secure-your-asp.net-core-2.0-api-part-1---issuing-a-jwt/

这里是主要代码:

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var token = new JwtSecurityToken(
                    issuer: "yourdomain.com",
                    audience: "yourdomain.com",
                    claims: user.Claims,
                    expires: DateTime.Now.AddMinutes(30),
                    signingCredentials: creds);

我不明白的部分是它在配置文件中查找键的位置,但它没有指示该键是/应该是什么?

【问题讨论】:

    标签: c# authentication asp.net-core jwt


    【解决方案1】:

    此密钥可以是任何字符串:它是用于加密和解密您的安全有效负载的密钥。 来自Wikipedia

    对称密钥算法是一种加密算法,它使用相同的密钥来加密明文和解密密文。实际上,密钥代表两方或多方之间的共享秘密,可用于维护私人信息链接。

    至于如何生成高效密钥,可以参考crypto.stackexchange上的这个问题。

    【讨论】:

      【解决方案2】:

      一种选择是保留与 JWT 标头中的“kid”声明相关联的对称签名密钥的存储库。例如,将密钥文件保存在加密的 AWS S3 存储桶中。 .NET Core 2 Web 服务每 X 分钟从 S3 存储桶中提取密钥文件。

      当请求到达时,“kid”声明值用于从从提取的文件构建的集合中查找关联的对称密钥。

      示例: 配置 IssuerSigningKeyResolver 函数。

      public static IServiceCollection AddJwtValidation(this IServiceCollection services)
      {
              IServiceProvider sp = services.BuildServiceProvider();
              ConfigRoot = sp.GetRequiredService<IConfigurationRoot>();
      
              tokenAudience = ConfigRoot["JwtToken:Audience"];
              tokenIssuer = ConfigRoot["JwtToken:Issuer"];
      
              SecurityKeyManager.Start();
      
              services.AddAuthentication(options =>
              {
                  options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                  options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                  }).AddJwtBearer(options =>
              {
                  options.Audience = tokenAudience;
                  options.ClaimsIssuer = tokenIssuer;
      
                  options.TokenValidationParameters = new TokenValidationParameters
                  {                    
                      // The signing key must match!
                      ValidateIssuerSigningKey = true,
                      RequireSignedTokens = true,
                      IssuerSigningKeyResolver = MyIssuerSigningKeyResolver,
                      ....
      

      IssuerSigningKeyResolver 定义为:

      public static List<SecurityKey> MyIssuerSigningKeyResolver(string token, SecurityToken jwtToken, string kid, TokenValidationParameters validationParameters)
      {
              List<SecurityKey> keys = new List<SecurityKey>();
      
              if (validationParameters == null)
              {
                  throw new ArgumentNullException("validationParameters");
              }
      
              if (jwtToken == null)
              {
                  throw new ArgumentNullException("securityToken");
              }
      
              if (!string.IsNullOrEmpty(kid))
              {
                  SymmetricSecurityKey key = SecurityKeyManager.GetSecurityKey(kid);
      
                  keys.Add(key);
              }
      
              return keys;
      }
      

      SecurityKeyManager 定期从 AWS S3 中提取密钥文件并将密钥存储在一个集合中。

      // Example approved-clients.txt file in the approved-clients S3 bucket (us-east-1).
      //    //kid,key,active
      //    customer1,AAAAAAAAAAAAAAAA,true
      //    customer2,BBBBBBBBBBBBBBBB,true
      //    customer3,CCCCCCCCCCCCCCCC,true
      //    customer4,DDDDDDDDDDDDDDDD,true
      
      namespace My.CoreServices.Security.Jwt
      {
          public class SecurityKeyManager
          {
              private const int RELOAD_TIMER_DELAY_SECONDS = 3 * 1000;
              private const int RELOAD_TIMER_PERIOD_MINUTES = 60 * 60 * 1000;
      
              [DebuggerDisplay("{Kid}  {SymmetricKey}  {Active}")]
              internal class ApprovedClient
              {
                  public string Kid { get; set; }
                  public bool Active { get; set; }
                  public string SymmetricKey { get; set; }
              };
      
              private static List<SymmetricSecurityKey> securityKeys = new List<SymmetricSecurityKey>();
      
              private static Timer reloadTimer = null;
      
              private static object keySync = new object();
      
              public static void Start()
              {
                  // Start a new timer to reload all the security keys every RELOAD_TIMER_PERIOD_MINUTES.
                  if (reloadTimer == null)
                  {
                      reloadTimer = new Timer(async (t) =>
                      {
                          try
                          {
                              List<ApprovedClient> approvedClients = new List<ApprovedClient>();
      
                              Log.Debug("Pulling latest approved client symmetric keys for JWT signature validation");
      
                              string awsAccessKeyId = JwtConfigure.ConfigRoot["AWS:KeyManagement:AccessKeyId"];
                              string awsSecretAccessKey = fromBase64(JwtConfigure.ConfigRoot["AWS:KeyManagement:SecretAccessKey"]);
                              string awsRegion = JwtConfigure.ConfigRoot["AWS:KeyManagement:Region"];
      
                              using (var client = new AmazonS3Client(awsAccessKeyId, awsSecretAccessKey, RegionEndpoint.GetBySystemName(awsRegion)))
                              {
                                  var request = new GetObjectRequest();
                                  request.BucketName = JwtConfigure.ConfigRoot["AWS:KeyManagement:Bucket"];
                                  request.Key = JwtConfigure.ConfigRoot["AWS:KeyManagement:Key"];
      
                                  var response = await client.GetObjectAsync(request);
      
                                  using (StreamReader sr = new StreamReader(response.ResponseStream))
                                  {
                                      while (sr.Peek() > 0)
                                      {
                                          string line = await sr.ReadLineAsync();
      
                                          // Ignore comment lines in the approved-client file
                                          if (!line.StartsWith("//") && !string.IsNullOrEmpty(line))
                                          {
                                              // Each line of the file should only have 3 items:
                                              // kid, key, active
                                              string[] items = line.Split(',');
                                              approvedClients.Add(new ApprovedClient()
                                              {
                                                  Kid = items[0],
                                                  SymmetricKey = items[1],
                                                  Active = Boolean.Parse(items[2])
                                              });
                                          }
                                      }
                                  }
      
                              }
                              lock (keySync)
                              {
                                  if (approvedClients.Count > 0)
                                  {
                                      // Clear the security key list and repopulate
                                      securityKeys.Clear();
      
                                      foreach (var approvedClient in approvedClients)
                                      {
                                          if (approvedClient.Active)
                                          {
                                              var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(approvedClient.SymmetricKey));
                                              key.KeyId = approvedClient.Kid;
                                              securityKeys.Add(key);
                                          }
                                      }
                                  }
                              }
      
                              Log.Information($"Reloaded security keys");
                          }
                          catch (Exception ex)
                          {
                              Log.Warning($"Error getting current security keys - {ex.Message}");
                          }
                      }, null, RELOAD_TIMER_DELAY_SECONDS, RELOAD_TIMER_PERIOD_MINUTES);
                  }
              }
      
              public static void Stop()
              {
                  if (reloadTimer != null)
                  {
                      reloadTimer.Dispose();
                      reloadTimer = null;
                  }
              }
      
              public static SymmetricSecurityKey GetSecurityKey(string kid)
              {
                  SymmetricSecurityKey securityKey = null;
      
                  lock (keySync)
                  {
                      byte[] keyData = securityKeys.Where(k => k.KeyId == kid).Select(x => x.Key).FirstOrDefault();
      
                      if (keyData != null)
                      {
                          securityKey = new SymmetricSecurityKey(keyData);
                          securityKey.KeyId = kid;
                      }
                  }
      
                  return securityKey;
              }
      
              private static string fromBase64(string encodedValue)
              {
                  byte[] decodedBytes = Convert.FromBase64String(encodedValue);
                  return Encoding.UTF8.GetString(decodedBytes);
              }
          }
      }
      

      确保在为特定用户/客户/等创建 JWT 时,在 JWT 标头中设置“kid”声明。

      {
        "alg": "HS256",
        "kid": "customer2",
        "typ": "JWT"
      }
      

      “kid”的值将作为第三个参数传递给 IssuerSigningKeyResolver 方法。然后,该孩子将用于查找用于验证 JWT 签名的关联对称密钥。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-04
        • 2021-12-07
        • 2021-06-27
        • 2016-08-28
        • 2019-05-21
        • 1970-01-01
        • 2018-11-08
        相关资源
        最近更新 更多