当前位置: 首页 > 知识库问答 >
问题:

如何获得JWK并在JWT签名中使用它们?

屈升
2023-03-14

我正在阅读这个关于JWTs的博客,以及如何使用它的签名部分来验证令牌是否确实是由受信任方颁发的。

https://hackernoon.com/json-web-tokens-jwt-demystified-f7e202249640

JSON Web Key(JWK)是一个JSON对象,其中包含一个众所周知的公钥,可用于验证签名的JWT的签名。

如果JWT的颁发者使用非对称密钥对JWT进行签名,那么它可能会托管一个名为JSON Web密钥集(JWKS)的文件。JWKS是一个JSON对象,它包含属性键,属性键又包含一个JWK对象数组。

下面是我的代码库中为我生成JWT的java代码片段:

new JwtBuilder().setClaims(claims).setExpiration(expiration).signWith(signatureAlgorithm, sharedSecret).compact();

我不太明白我如何获得JWK,以及如何使用它们进行签名?我在网上没有找到任何例子。

任何帮助都将不胜感激。

共有2个答案

殳越
2023-03-14
package com.java;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Enumeration;

import org.jose4j.json.internal.json_simple.parser.ParseException;
import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.keys.resolvers.JwksVerificationKeyResolver;
import org.jose4j.keys.resolvers.VerificationKeyResolver;
import org.jose4j.lang.JoseException;

public class JWTSigning2 {

    public static void main(String args[]) throws Exception {

        String jwt = generateJWT();
        validateJWTwithJWKS(jwt);
    }

    private static String generateJWT() throws FileNotFoundException, KeyStoreException, IOException,
            NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, JoseException {

        JwtClaims jwt_claims = new JwtClaims();

        jwt_claims.setSubject("sub");
        jwt_claims.setIssuer("https://domain");
        jwt_claims.setIssuedAtToNow();
        jwt_claims.setExpirationTimeMinutesInTheFuture(1000000);
        jwt_claims.setGeneratedJwtId();
        jwt_claims.setClaim("sid", "sessionid");
        jwt_claims.setClaim("email", "test@mail.com");
        jwt_claims.setClaim("given_name", "first");
        jwt_claims.setClaim("family_name", "last");

        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload(jwt_claims.toJson());
        String KeyPassword = "p12-key-password";
        File file = new File("path-to-key.p12");
        InputStream stream = new FileInputStream(file);
        KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
        store.load(stream, KeyPassword.toCharArray());
        Enumeration e = store.aliases();
        String alias = (String) e.nextElement();
        PrivateKey key = (PrivateKey) store.getKey(alias, KeyPassword.toCharArray());
        jws.setKey(key);
        jws.setKeyIdHeaderValue("1");
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_PSS_USING_SHA512);
        jws.setHeader("typ", "JWT");

        String jwt = jws.getCompactSerialization();
        System.out.println(jwt);

        return jwt;
    }

    private static void validateJWTwithJWKS(String jwt) throws JoseException, FileNotFoundException, IOException,
            ParseException, InvalidJwtException, MalformedClaimException {

        JsonWebKeySet jsonWebKeySet = new JsonWebKeySet("json-jwks-escaped");
        VerificationKeyResolver verificationKeyResolver = new JwksVerificationKeyResolver(jsonWebKeySet.getJsonWebKeys());

        JwtConsumer jwtConsumer = new JwtConsumerBuilder().setVerificationKeyResolver(verificationKeyResolver).build();

        JwtClaims claims = jwtConsumer.processToClaims(jwt);
        System.out.println("sub:- " + claims.getSubject());
    }

}
徐晔
2023-03-14

每个开放式id服务器都必须为租户提供如下endpoint:

  https://--YOUR DOMAIN----/.well-known/jwks.html" target="_blank">json

如果您访问这个endpoint,您将看到json格式的endpoint

{
  keys: [
    {
      alg: 'RS256',
      kty: 'RSA',
      use: 'sig',
      n: 'tTMpnrc4dYlD8MtmPnW3xZNbLxkaGCUwTqeKB4dfLg11dEpMyQEc4JRxUvRzp9tz00r6lkZ1ixcvIiuB_eMVckU8VyFSFWBSAxp5duBk6lRpYk-QjK3kEdPxYLxyW84gNzwMi-XW8zxJbsOa-cRM9sCb62Qz2yfWoQfimoFXsCnVHq496kizO7gZ972JefvTce1_n9dd_1p0K6c14qcCXtF6hbA_gQ0N7h3IyloBqiusKyTsV-ZrMZDldZkI-4v7s49TdcRZgEOvSapMz5YyoDvAWzuWGEiljkjkCOo0Mr5Sioi2x0dBm6nJ2WVYfZrwEF5J',
      e: 'AQAB',
      kid: 'NTY2MjBCNzQ1RTLPQzk3NzczRRTMQ0E4NzE2MjcwOUFCRkUwRTUxNA',
      x5t: 'NTY2MjBCNzQ1RTJPLzk3NzczRUNPO0E4NzE2MjcwOUFCRkUwRTUxNA',
      x5c: [Array]
    }
  ]
}

x5c是什么?

x5c(X.509证书链)Header参数包含X.509公钥证书或证书链[RFC5280],对应于用于对JWS进行数字签名的密钥。证书或证书链表示为证书值字符串的JSON数组。数组中的每个字符串都是基数64编码的(不是基数64url编码的)DER[ITU. X690.2008]PKIX证书值。包含与用于对JWS进行数字签名的密钥相对应的公钥的证书必须是第一个证书。随后可能会有其他证书,每个后续证书都是用来证明前一个证书的证书。收件人必须根据RFC 5280[RFC5280]验证证书链,如果发生任何验证失败,则认为证书或证书链无效。使用此Header参数是可选的。

如果你检查x5c数组,你会看到很长的字符串。你必须取这个值,并为每个64个值分开它们。这很简单。这里有一个例子:

          -----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIJY5XAn120Mst4MA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV
BAMTFmRl2e11ZGlrdGt5Mi5hdXRoMC5jb20wHhcNMTkwOTI5MjAxNjE4WhcNMzMw
NjA3MjAxNjE4WjAhMR8wHQYDVQQDExZkZXYtdWe3a3RreTIuYXV0aDAuY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AeIIBCgKCAQEAtTMpnrc4dYlD8MmPnW3xZNbL
xkaGCUwTqeKB4etLg11dEpMyQEc4JRxUvRzp9t656lkZ1ixcvIiuB/eMVckU8VyF
SFWBSAxp5vrBk6lRpYk+QjK3kEdA9PxYLxyW84gNzwMi+XW8zxJbsOa+cRM9sCb6
2Qz2fWoQfimoFXsCnVHq496kp93izO7gZ972JefvTce1/n9dd/1p0K6c14qcCXtF
6hbA/gQ0N7h3IyloBqiusKyTsV+ZrMZDldZkI+4v7s49TdcRZgEOvSapMz5YyoDv
AWzuWGEilCOo0Mr5Sioi2x0dBm6nJ2WVYfZrwEF5JTz9LlKjYAqJ6ETGYKhjkwID
AQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQme5xBKaloQKQr5oxt
7uRlWthe6jAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADopEBABpfpizn
MSJ67HDX358Rav5CYFEeIBeHXrxDQLprKdNzNSxOJ6tRpk6OF0Qs52wCEbrUXYBu
MRjmmmvN3bBHGMmq/g4VPZGDLh/JF5xJjRj13um8Rfua3S2NE4nZUYfPWctk56mN
UUQ9DUkbPRbLEJKCqVSQNagk6TEGe4dfRGdUNvAzDBglMTFOSrY1GAOJdUA1+bPb
3MnSdfyIyxSfPK5oDSQ4puMWKme2ZdGGPj+urSxs1Tuwkv0DxohdV+35WUIJcJPU
ARJecLX7rjyAzqqZE1sJGfsY5ob09380/BTAwHHP/KjiOFhilJ5OoHiU62D+mEKA
DHqlJzoj1VX/3d8=
                -----END CERTIFICATE-----

因此,当您开始验证过程时:

//you get the token
//you decode the token
//you compare the kid which is in the header of the token

//jwk.kid the one that you get when you visit the /.well-known url above
if (jwk.kid === decodedToken.header.kid){
// in verification process you have to use the decoded code and the certificate 
// to verify the signature

}

此过程特定于“RS256”算法。RS256生成非对称签名,这意味着必须使用私钥对JWT进行签名,并且必须使用不同的公钥来验证签名。与对称算法不同,使用RS256可以保证Auth0是JWT的签名者,因为Auth0是唯一拥有私钥的一方。为了验证对称算法,必须使用私钥。

 类似资料:
  • 我想知道是否有一个示例C代码或库可以使用RSA公钥验证我的JWT令牌签名。我找不到任何涉及C的示例 openssl for C没有任何与RSA相关的示例。 谢谢

  • 我有一个由keyCloack生成的JWT,RS256,类似这样的东西 样本: 我需要使用KeyClock证书解码和验证此令牌。 我可以通过api获得KeyClock证书。 在响应中,我有x5c字段。 我可以验证这个jwthttps://jwt.io/如果我把x5c部件放在----证书----标签内 如何在Java中验证同样的事情? 我尝试了几件事,但都失败了。

  • 在PHP中,我试图使用AWS的RSA公钥(我在https://cognito-identity.amazonaws.com/.well-known/jwks_uri). 密钥以适当的页眉/页脚开始,然后开始RSA公钥等等。我查看了一些PHP库,如Emarref\Jwt\Jwt\code>,但是我发现了错误:。这一切归结为基本的php函数:。 我已经研究了php。net/manual进行openss

  • 问题内容: 我对sql中的别名有疑问和疑问。如果我想在同一查询中使用别名,可以使用它。例如:考虑表名xyz与列a和b 这有可能吗? 问题答案: 您是在谈论给查询中的表达式赋予标识符,然后在查询的其他部分重用该标识符吗? 在Microsoft SQL Server中这是不可能的,而我几乎所有的SQL经验都仅限于此。但是您可以执行以下操作。 显然,该示例并不是特别有用,但是如果您在多个地方使用该表达式

  • 我正在尝试使用pdfbox库签署pdf。我现在卡住了,真的需要帮助。 这是我的代码: 然后我正在保存我的pdf,但是:1)我注意到sign method从来没有被调用2)我应该在哪里附加CertyFicate?在sign method中? 以下是我保存PDF的方法: