使用公钥/私钥进行IdentityServer客户端身份验证而不是共享密钥。

11

我正在尝试使用公共/私有密钥来代替IdentityServer4中客户端密钥的共享秘密。可以在这里找到此方法的文档。

如果是共享秘密,请求将包含明文的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

我的问题是:使用公钥/私钥身份验证方法时,应传递什么作为secret

为了提供一些背景信息,使用公钥/密钥身份验证的客户端将通过以下步骤向IdentityServer进行注册

  1. 客户端生成一个.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" }
    };
    

    你提到了一个 server.crt 文件。这是打字错误还是一个不同的文件?那么作为客户端密钥使用的 crt 文件是哪个(我猜测是 client.crt)? - fra
    1
    抱歉,那是一个打字错误...已经修正了。 - ubi
    2个回答

    12

    通过 IdentityServer4 中的单元测试,我弄清楚了这个问题!

    在使用公共/私有身份验证时,不使用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());
    

    3

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接