使用 public/private 密钥而不是共享密钥的 IdentityServer 客户端身份验证
IdentityServer client authentication with public/private keys instead of shared secrets
我正在尝试使用 public/private 密钥而不是 IdentityServer4 的客户端机密的共享机密。这种方法已记录 here。
如果它是共享机密,请求将以纯文本形式包含 secret
。例如
curl -X POST \
http://<identityserver>/connect/token \
-F client_id=abc \
-F client_secret=secret \
-F grant_type=client_credentials \
-F scope=api1 api2
我的问题是:使用 public/private 密钥验证方法应该作为 secret
传递什么?
为了提供一些背景信息,使用 public/key 身份验证的客户端将通过以下步骤向 IdentityServer 注册
客户端生成一个 .crt
文件,例如
// create key
$ openssl genrsa -des3 -passout pass:x -out client.pass.key 2048
$ openssl rsa -passin pass:x -in client.pass.key -out client.key
// create certificate request (csr)
$ openssl req -new -key client.key -out client.csr
// create certificate (crt)
$ openssl x509 -req -sha256 -days 365 -in client.csr -signkey client.key -out client.crt
// export pfx file from key and crt
$ openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt
客户端将与 IdentityServer
共享 client.crt
文件
IdentityServer 将通过
注册客户端
var client = new Client
{
ClientId = "abc",
ClientSecrets =
{
new Secret
{
Type = IdentityServerConstants.SecretTypes.X509CertificateBase64,
Value = "MIIDF...." <================= contents of the crt file
}
},
AllowedGrantTypes = GrantTypes.ClientCredentials,
AllowedScopes = { "api1", "api2" }
};
我认为它必须是签名的 JWT。查看 IDS4 代码库中的 PrivateKeyJwtSecretValidator class:
感谢 IdentityServer4 中的单元测试!
使用public/private认证时,不使用client_secret
。相反,使用了 client_assertion
,这是一个 JWT 令牌。
这是令牌请求的示例代码。 client.pfx
是问题中上述步骤生成的证书包。
var now = DateTime.UtcNow;
var clientId = "abc";
var tokenEndpoint = "http://localhost:5000/connect/token";
var cert = new X509Certificate2("client.pfx", "1234");
// create client_assertion JWT token
var token = new JwtSecurityToken(
clientId,
tokenEndpoint,
new List<Claim>
{
new Claim("jti", Guid.NewGuid().ToString()),
new Claim(JwtClaimTypes.Subject, clientId),
new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64)
},
now,
now.AddMinutes(1),
new SigningCredentials(
new X509SecurityKey(cert),
SecurityAlgorithms.RsaSha256
)
);
var tokenHandler = new JwtSecurityTokenHandler();
var tokenString = tokenHandler.WriteToken(token);
// token request - note there's no client_secret but a client_assertion which contains the token above
var requestBody = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"client_id", clientId},
{"client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
{"client_assertion", tokenString},
{"grant_type", "client_credentials"},
{"scope", "api1 api2"}
});
var client = new HttpClient();
var response = await client.PostAsync(tokenEndpoint, requestBody);
var tokenRespone = new TokenResponse(await response.Content.ReadAsStringAsync());
我正在尝试使用 public/private 密钥而不是 IdentityServer4 的客户端机密的共享机密。这种方法已记录 here。
如果它是共享机密,请求将以纯文本形式包含 secret
。例如
curl -X POST \
http://<identityserver>/connect/token \
-F client_id=abc \
-F client_secret=secret \
-F grant_type=client_credentials \
-F scope=api1 api2
我的问题是:使用 public/private 密钥验证方法应该作为 secret
传递什么?
为了提供一些背景信息,使用 public/key 身份验证的客户端将通过以下步骤向 IdentityServer 注册
客户端生成一个
.crt
文件,例如// create key $ openssl genrsa -des3 -passout pass:x -out client.pass.key 2048 $ openssl rsa -passin pass:x -in client.pass.key -out client.key // create certificate request (csr) $ openssl req -new -key client.key -out client.csr // create certificate (crt) $ openssl x509 -req -sha256 -days 365 -in client.csr -signkey client.key -out client.crt // export pfx file from key and crt $ openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt
客户端将与 IdentityServer
共享 IdentityServer 将通过
注册客户端var client = new Client { ClientId = "abc", ClientSecrets = { new Secret { Type = IdentityServerConstants.SecretTypes.X509CertificateBase64, Value = "MIIDF...." <================= contents of the crt file } }, AllowedGrantTypes = GrantTypes.ClientCredentials, AllowedScopes = { "api1", "api2" } };
client.crt
文件
我认为它必须是签名的 JWT。查看 IDS4 代码库中的 PrivateKeyJwtSecretValidator class:
感谢 IdentityServer4 中的单元测试!
使用public/private认证时,不使用client_secret
。相反,使用了 client_assertion
,这是一个 JWT 令牌。
这是令牌请求的示例代码。 client.pfx
是问题中上述步骤生成的证书包。
var now = DateTime.UtcNow;
var clientId = "abc";
var tokenEndpoint = "http://localhost:5000/connect/token";
var cert = new X509Certificate2("client.pfx", "1234");
// create client_assertion JWT token
var token = new JwtSecurityToken(
clientId,
tokenEndpoint,
new List<Claim>
{
new Claim("jti", Guid.NewGuid().ToString()),
new Claim(JwtClaimTypes.Subject, clientId),
new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64)
},
now,
now.AddMinutes(1),
new SigningCredentials(
new X509SecurityKey(cert),
SecurityAlgorithms.RsaSha256
)
);
var tokenHandler = new JwtSecurityTokenHandler();
var tokenString = tokenHandler.WriteToken(token);
// token request - note there's no client_secret but a client_assertion which contains the token above
var requestBody = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"client_id", clientId},
{"client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
{"client_assertion", tokenString},
{"grant_type", "client_credentials"},
{"scope", "api1 api2"}
});
var client = new HttpClient();
var response = await client.PostAsync(tokenEndpoint, requestBody);
var tokenRespone = new TokenResponse(await response.Content.ReadAsStringAsync());