为 JWT 存储 RSA256 密钥

Storing RSA256 keys for JWT

我在为 Json Web 令牌 (JWT) 存储 RSA256 私有和 public 令牌时遇到问题。

我正在使用 jsonwebtoken.io,我创建了令牌,并且能够使用已作为文本存储在我的数据库中的私钥和 public 密钥来验证令牌。

   public String createJWTToken(Map<String, Object> claims) {
        if (replaceAt.isBefore(Instant.now())) {
            loadKeyFromStorage();
        }

        String jws = Jwts.builder()
                .setHeaderParam(JwsHeader.KEY_ID, currentKid)
                .setHeaderParam(JwsHeader.ALGORITHM, algorithm)
                .setClaims(claims)
                .signWith(currentPrivateKey, algorithm)
                .compact();

        Jws<Claims> claimsCheck = Jwts.parserBuilder().setSigningKey(currentPublicKey).build().parseClaimsJws(jws);
        return jws;
    }

但是,如果我将令牌带到 JWT.io 并尝试使用我的 public 密钥验证它,它会说它无效。 我的 JWT 令牌

eyJraWQiOiI1Njg3YmM0NS00ZjVlLTQ2ZDQtYTlmZi0yZjA2NjM4MWIxNjYiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJITVpTbTJjdkVMQ0dSeWJnN0JlQSIsImF1ZCI6ImJGZXdyYlBSdFl1QVQ3cjVsNWQ0IiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmFyY2hpcGVsYWdvLmJ1aWxkIiwic2NvcGVzIjoiIiwiZXhwIjoxNjE1MTc0MzgyLCJpYXQiOjE2MTI1ODIzODJ9.CKIe_kWSFGqkghqfJDIXtAqKVbrvKlMsdbeYNsl_AaoHjUmMYPqzchHPmMzVDUsDZEg8iugH6Og5nxFJBiONxr6Bt1h7J-yUF1-9DHJ2SNrtcJdWpzWrn0FUocXpTFpysxBTw9eaVc988z6XGG2MQtfJyEzLgAFJXBrPp-kM9guP8CvZhf1OuDzDGtvVl3ig2P3AQaWod6O6f-VUWDD6khmymYFikiDMk9KGW5eMmlPqJqHy3NyCO8vEDb9c0DGWkQL4dSA-gpqbzERN8303SLYI47PTbI0b-t7wxzYaCN4-GvSy8Gwp0hfN9VzFCMJ6pWc6a7HJinwNUDUWRTQ_nA

私钥

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCM7pSzSVJgZql7vAIBFsJ3k1CKr7PnsEFrn1VpdBs+Anu8wOOwJ7sKmOSwpMembh6EIU9vv4Xi5GMHQNn+y7+1p8ktFOqPYzyLWK2pISJTOMJRYbZmPZRrJLXubQntiFHqRuHkhB9VZ16Yj7Pbsy7TnHAE1ypZkwcVOxNObOiGIGwy1MD9+ayc0ciPJQXX67bsIZhPwzuY1uSfaTm1qEPqDa//LQU8TcgHoQzXjDT++n5WssI2GXX/kFDvkMaa8YibY3LHMlOHKtfnVyQ2Jh7gqsiIEzasRHOCBG3FPaGPMJH0KjElC9cfHdfRzpnRZ5AGZnpybLRNLrMjwV/7kYApAgMBAAECggEAU4oZGy2bZwlz7aTEi2CyZa8tTwhX3D7eiK0qNBhfDaLrNjggv4rNlLqM1SjYMA+Whzw3mkYtVxGKogIPNroQKd4Lom2DnPt2KCOozViWwD4k8Zi6RmC6WcipD2wTNnpYFEdwH8Uxza44pLaKJvFQEJ/qxvPEZtSAnlUmXJayPs6Xp7Pm1Pix4bp2i/Ozsd17sYv0+GFPRTf0JT3u6KhKNTERyZ9XxKwglww7LfGZQKVF0VxS/12ok7egX2LN1T8cDIo53H3oyxuFsAHQ+RcPDXrx6KRUou6a7CD+mX+WDKJOxguw90kSUBfJeb5pX6p+KgALln5onzsgycxP1E2fAQKBgQDK3ii08i/ymjRc/j6uiIYR0twe3/xymMx9vx4wc0sTolao+llvJPcNyC6poag2DV+ciCEf9EvwJBYwwEu6+4xoi+q8mnRhS5Twh9pNQeg1F4ST1JvURWX4HaCPtHImTeJ23bCymrDmW8SdT2qIATpAwCsxLs5OaEJncbAuGUQBSwKBgQCx18JNx63Yn6JSOA38zxKusyiKsxvtcC1zVg1UE2W1x4kC1hxUD7i/tamEJSW9qer4pJdMdcda74I3pppcpnq7L7Ga7YjFd93pZ9+FlzGhASz1NF/I1pxIL0boOUthBruUSOjlAVO1IYrTfNsxPvchK0Bqbv4j6A+45TkXhVMP2wKBgDwl6D3V/L9aVyInQ6Bt3ApW0WraEDhN83to+eN1m5HjtPv+1httA07zxloHEx+LkYiQl/mobgdyO54StaFnybaJnXxz8wOR7EPwk5oKa3WqVmWaSOWD+fq5lgxlfN68guOpUSVzVfXGyaG2lShj7Mib8XJwpTx8Dwwqmgjg9tfHAoGBAIBLdAKEYCd70a+afIy6HXImEMMuPqFlYYRouajDbYZbcb24FCuYQ+EY/jc0TSur3rSMmBEyjiRN0BSxfX4FI1jSKT/ox9gchtwQcTGARu8tV+90Xv0VxRxV7sMsQfK21q88gbZi5K4wimPTGJVIJSOqfgfKFlB04pKx2iPbrHYtAoGAFwyBVopeMNCbDyEtO6eDGuBAnOaG1SHy0r/K9FN007/2Ha7tXFBfAP7++3ecYcPmHswk33y1xQFcc9bIWH8m2jBdU6zhl5fi6UA9CNaxl4FBlyfNWxLjenxEYd2SWHQLzX2cBJSTM3SVZsM5h/1jk04DFGp0nwfkl8d/8/3UslE=

public键

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjO6Us0lSYGape7wCARbCd5NQiq+z57BBa59VaXQbPgJ7vMDjsCe7CpjksKTHpm4ehCFPb7+F4uRjB0DZ/su/tafJLRTqj2M8i1itqSEiUzjCUWG2Zj2UayS17m0J7YhR6kbh5IQfVWdemI+z27Mu05xwBNcqWZMHFTsTTmzohiBsMtTA/fmsnNHIjyUF1+u27CGYT8M7mNbkn2k5tahD6g2v/y0FPE3IB6EM14w0/vp+VrLCNhl1/5BQ75DGmvGIm2NyxzJThyrX51ckNiYe4KrIiBM2rERzggRtxT2hjzCR9CoxJQvXHx3X0c6Z0WeQBmZ6cmy0TS6zI8Ff+5GAKQIDAQAB

这就是我创建密钥的方式

    private JWKKey createNewKey() {
        KeyPair keyPair = Keys.keyPairFor(algorithm);
        JWKKey key = JWKKey.builder()
                .kid(UUID.randomUUID().toString())
                .privateKey(Encoders.BASE64.encode(keyPair.getPrivate().getEncoded()))
                .publicKey(Encoders.BASE64.encode(keyPair.getPublic().getEncoded()))
                .expiresAt(Instant.now().plusSeconds(KeyLifeSpan))
                .build();

        dynamoDB.putItem(new PutItemRequest(keysTableName, ImmutableMap.<String, AttributeValue>builder()
                .put(DBK.KID, AV.of(key.getKid()))
                .put(DBK.EXPIRES, AV.of(key.getExpiresAt()))
                .put(DBK.PRIVATE_KEY, AV.of(key.getPrivateKey()))
                .put(DBK.PUBLIC_KEY, AV.of(key.getPublicKey()))
                .build()));

        return key;
    }

这就是我从数据库加载密钥的方式

    private void setKeyUsage(JWKKey key) {
        currentKid = key.getKid();
        replaceAt = key.getExpiresAt().minusSeconds(longestTokenLife);
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            currentPrivateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key.getPrivateKey().getBytes(StandardCharsets.UTF_8))));
            currentPublicKey = kf.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(key.getPublicKey().getBytes(StandardCharsets.UTF_8))));
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

经过几天的尝试,我发现 jwt.io 要求 public 密钥以“-----BEGIN RSA PUBLIC KEY-----”开头并结束使用“-----END RSA PUBLIC KEY-----”