用于JWT承载认证的.NET Core IssuerSigningKey文件

mon*_*nty 16 c# authentication jwt asp.net-core

我正在努力实现(或理解)JWT承载令牌认证的签名密钥.我希望有人可以帮助我或解释我的错误.

在过去的几周里,我抓了大量的教程,设法让一个自定义的Auth-Controller运行,它发出我的令牌并设法建立JWT承载认证来验证标题中的令牌.

有用.

我的问题是所有示例和教程要么生成随机或内存(发行者)签名密钥,要么使用硬编码的"密码"字符串或从某些配置文件中获取它们(在代码示例中查找"密码").

我的意思是验证设置(在StartUp.cs中):


  //using hardcoded "password"
  SecurityKey key = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes("password"));

  app.UseJwtBearerAuthentication(new JwtBearerOptions
  {
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = new TokenValidationParameters
    {
      ValidateIssuer = true,
      ValidIssuer = "MyIssuer",
      ValidateAudience = true,
      ValidAudience = "MyAudience",
      ValidateLifetime = true,
      IssuerSigningKey = key
    }
  });
Run Code Online (Sandbox Code Playgroud)

在创建令牌的AuthController中:


  //using hardcoded password
  var signingKey = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes("password"));
  SigningCredentials credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

  var jwt = new JwtSecurityToken     // Create the JWT and write it to a string
  (
    issuer: _jwtTokenSettings.Issuer,
    audience: _jwtTokenSettings.Audience,
    claims: claims,
    notBefore: now,
    expires: now.AddSeconds(_jwtTokenSettings.LifetimeInSeconds),
    signingCredentials: credentials
  );
Run Code Online (Sandbox Code Playgroud)

这个问题中他们使用了:

RSAParameters keyParams = RSAKeyUtils.GetRandomKey();
Run Code Online (Sandbox Code Playgroud)

我(当前)的假设是,在生产中,您不应该使用硬编码字符串或配置文件中的字符串作为令牌签名密钥.而是使用一些证书文件??? 我错了吗?

所以我尝试用在auth控制器中工作的证书替换字符串:


  //using a certificate file
  X509Certificate2 cert = new X509Certificate2("MySelfSignedCertificate.pfx", "password");
  X509SecurityKey key = new X509SecurityKey(cert);
  SigningCredentials credentials = new SigningCredentials(key, "RS256");

  var jwt = new JwtSecurityToken      // Create the JWT and write it to a string
  (
     issuer: _jwtTokenSettings.Issuer,
     audience: _jwtTokenSettings.Audience,
     claims: claims,
     notBefore: now,
     expires: now.AddSeconds(_jwtTokenSettings.LifetimeInSeconds),
     signingCredentials: credentials
  );
Run Code Online (Sandbox Code Playgroud)

但似乎无法使用证书进行验证.


  X509Certificate2 cert = new X509Certificate2("MySelfSignedCertificate.pfx", "password");
  SecurityKey key == // ??? how to get the security key from file (not necessarily pfx)

  app.UseJwtBearerAuthentication(new JwtBearerOptions
  {
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = new TokenValidationParameters
    {
      ValidateIssuer = true,
      ValidIssuer = "MyIssuer",
      ValidateAudience = true,
      ValidAudience = "MyAudience",
      ValidateLifetime = true,
      IssuerSigningKey = key
    }
  });
Run Code Online (Sandbox Code Playgroud)

我错了,我应该使用证书作为签名密钥吗?当auth控制器与消费/安全的web api不同的服务器上时,我还能如何更改生产中的签名密钥(可能有一次,现在不是)?

似乎我也错过了这个问题的答案(必修步骤).


现在我让它运行我仍然错过了它应该是那样的点吗?


值得注意的是:未找到文件(部署到服务器后)

对于所有使用它的人来说,它从Visual Studio启动时有效但在部署到服务器/ azure之后它会显示"找不到文件":

阅读并upvote这个问题:X509证书没有在服务器上加载私钥文件


值得注意的是2:基于令牌的身份验证实际上并不需要它

公钥不需要在API端.它将自动通过身份验证服务器的发现端点进行检索.

mon*_*nty 12

哦亲爱的,那很简单:

SecurityKey key = new X509SecurityKey(cert);
Run Code Online (Sandbox Code Playgroud)

或者作为上面的完整样本:

X509Certificate2 cert = new X509Certificate2("MySelfSignedCertificate.pfx", "password");
SecurityKey key = new X509SecurityKey(cert); //well, seems to be that simple
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = "MyIssuer",
        ValidateAudience = true,
        ValidAudience = "MyAudience",
        ValidateLifetime = true,
        IssuerSigningKey = key
     }
});
Run Code Online (Sandbox Code Playgroud)


Sly*_*hon 7

非常重要的一点是,如果您使用证书文件,虽然服务器需要带有私钥的文件,但客户端应该只使用公钥。

您不想将您的私钥文件提供给任何人;他们只需要公钥。

// On client
var publicCert = new X509Certificate2("MySelfSignedCertificate.cer");
var publicKey = new X509SecurityKey(publicCert);
...
    IssuerSigningKey = publicKey
Run Code Online (Sandbox Code Playgroud)

将 PFX(私有)转换为 CER(公共)的最简单方法可能是导入到 Windows 证书管理器中,然后仅使用公钥导出。

从命令行,您还可以使用 PowerShell 5 创建(PowerShell 6 中尚不支持):

Get-PfxCertificate -FilePath MySelfSignedCertificate.pfx | Export-Certificate -FilePath MySelfSignedCertificate.cer
Run Code Online (Sandbox Code Playgroud)

或者,您可以安装并使用 OpenSSL 从命令行进行转换。

注1:正如您所发现的,一旦您设置了Authority,自动发现也许能够从服务器上找到公钥。

注意 2:除了将证书存储在文件中之外,您还可以将其存储在 Windows 证书存储中,并通过指纹引用它(PFX 和 CER 文件都可以导入)。