使用现有私钥和RS256算法生成JWT

时间:2018-03-16 22:10:05

标签: java jwt private-key

我有以下RSA私钥,我必须生成一个JWT 令牌使用 RS256算法

以下是我的示例私钥

-----BEGIN RSA PRIVATE KEY----- /
MIIEoAIBAAKCAQEAnFWdIwBbLRw4xfFDXYFmlXKB4BpKeuAtfh1dcs5mhod0WTo/
i/Z4DOpiiw/2H05luI4PzOZem8AlHI9hUhHq5p1+YHM68SyvBQ9OTl+O90nmLYOt
2Jzquks11bf29nJh7KwGVHOv2nh3eL39BVsqHSt0O/rjSa0bV+QtUc2DP9U4WzZ3
8RhT2bdiRcsDuMfI024u9JGG/O4iG3wDlXyS5j6G0NVw/KEJJtYYv8ruQVpvlKUd
Ntx7aE+u6F60SjJYQSfdjMoQNMDglBFwhY11RlHSmiJ/Ym8aE+Hj11JHhPcB1N+X
RWaHV9ply4TnE13PsQtGWVKsLDNQNUeIUljKdQIDAQABAoIBAAa4d3owYxBcDOTA
K7vdUDekezN9wy3nwozlXkW33G3JbOsDt1pLoiWL/eh/Kyl1XqdsaVQkTco28bbP
Qx5wFBUN4tzqlzdpoFcrV/EZPTV268+RFZbLnXDyGBez7N3zVNpZGtHj7JoLtmHD
vm4jLnr1NJik1G3aZI6GtJwLpaocwtKWHB59hVwF5NinW6BXN0ALNfwKwU4vMWYo
I65F2zvGMVl9rbfvU+E73DXK3TN5tLOAkqZMQ8+g/VnNd/XuZwh2ZADokEXV8aNR
7zVm3MCCcaa8IKJMrgnb9q47tzfyaoIu5aRYGYKZ/8wuItv4Dal30MK1CQoCD8cD
5uzorQECgYEA9+QTCXrVHzhJJm+QWQZrXu7ydk+tEix7WY9ZY702OHiTO2x9IT4d
4lKFbLhQrQMAFhO3B31Hq5ODGS4jB3bFzATrtOR9eLCR7l+0Az2FcU1Zmqsdkyv8
zlkD9oOYif6rICrVyLQ/lbQF7erVDRbxJUjeKqGAnvELrlzcr+rx+XECgYEAoXLQ
MdR+OLsP5XbcoA//Z2pgwwKZVs282MfYjZLVqeEAAC8BB9+8HHrtMaJGvADI06OV
7lTCDaE8UlqgzN2B55FmCTiLABjhk3fEDrhGVe4jhEZz1i8t0ArjsYTwXs/uXoUz
YP2rcJtkybOQEzjbvM4s5+B8iht+dYaqwoW5/0UCgYAp68UYZlBiXjdoq5dCpuZD
gK86ONEw8JrPk4Fvb5EazbFAbGFg3Mta+c+cijMCfy5ljWH3f0U+i8yw1m+QFJLw
pKhjx/w8C8gyArdDkQTfG1Ca6nMu71JqZv1Xk/uY4pt37iaHMYxLOc2C5aKv+wA+
6OrBVNyWhHcQPp4Hlfjj0QJ/de5oJf4SNV5vPi6U+la1OdV62PgNCls+lxtkFAYu
DOlOFtQ+7IGB50vj912STcJE8FOOMYm4NjyQ05df3kXvnjeXUST8ZBXIsO/LRvVU
a3CIgRb1hn7v+Af8Sq/Q5XD9rg2eejrSAG+CL9P6ahAecswoATj5v+hVd4PnODB2
rQKBgAwe3pkQRFHjameLHip+xcHQ85aASiLjhTvFhFjRHDpJ+FoiJ2H4xi4/jd1F
KGrhMpVnLXKwe1HaONFPV3yEFK2da1r66iIr/opcx1hyKmV1xvebcUxYYoRY6j/g
JMsceBR10oGEath+43rS78LASIQG83PmTYhkcEkQNftxEGqC
-----END RSA PRIVATE KEY-----

标题

{
  "alg": "RS256",
  "typ": "JWT"
}

正文

{
  "iss": "14a2fecb-ddd7-4823-46e2-67515bc01734",
  "sub": "13f7982d-1f78-46e2-4823-3273568fce89",
  "iat": 1521132568,
  "exp": 1522136156,
  "aud": "account-d.example.com",
  "scope": "signature"
}

以下是我的示例Java代码:

package com.knyc.demo;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.util.encoders.Base64;
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.jsonwebtoken.*;
import java.util.Date;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
public class GenerateJwtToken implements Callable{  
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public String onCall(MuleEventContext eventContext) throws Exception {
        String issuer = "14a2fecb-ddd7-4823-a9cc-67515bc01734";
        String scope = "signature";
        String subject = "13f7982d-1f78-46e2-a843-3273568fce89";
        String audience = "account-d.docusign.com";
        String privateKeyPEM ="-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEoAIBAAKCAQEAnFWdIwBbLRw4xfFDXYFmlXKB4BpKeuAtfh1dcs5mhod0WTo/\n" +
"i/Z4DOpiiw/2H05luI4PzOZem8AlHI9hUhHq5p1+YHM68SyvBQ9OTl+O90nmLYOt\n" +
"2Jzquks11bf29nJh7KwGVHOv2nh3eL39BVsqHSt0O/rjSa0bV+QtUc2DP9U4WzZ3\n" +
"8RhT2bdiRcsDuMfI024u9JGG/O4iG3wDlXyS5j6G0NVw/KEJJtYYv8ruQVpvlKUd\n" +
"Ntx7aE+u6F60SjJYQSfdjMoQNMDglBFwhY11RlHSmiJ/Ym8aE+Hj11JHhPcB1N+X\n" +
"RWaHV9ply4TnE13PsQtGWVKsLDNQNUeIUljKdQIDAQABAoIBAAa4d3owYxBcDOTA\n" +
"K7vdUDekezN9wy3nwozlXkW33G3JbOsDt1pLoiWL/eh/Kyl1XqdsaVQkTco28bbP\n" +
"Qx5wFBUN4tzqlzdpoFcrV/EZPTV268+RFZbLnXDyGBez7N3zVNpZGtHj7JoLtmHD\n" +
"vm4jLnr1NJik1G3aZI6GtJwLpaocwtKWHB59hVwF5NinW6BXN0ALNfwKwU4vMWYo\n" +
"I65F2zvGMVl9rbfvU+E73DXK3TN5tLOAkqZMQ8+g/VnNd/XuZwh2ZADokEXV8aNR\n" +
"7zVm3MCCcaa8IKJMrgnb9q47tzfyaoIu5aRYGYKZ/8wuItv4Dal30MK1CQoCD8cD\n" +
"5uzorQECgYEA9+QTCXrVHzhJJm+QWQZrXu7ydk+tEix7WY9ZY702OHiTO2x9IT4d\n" +
"4lKFbLhQrQMAFhO3B31Hq5ODGS4jB3bFzATrtOR9eLCR7l+0Az2FcU1Zmqsdkyv8\n" +
"zlkD9oOYif6rICrVyLQ/lbQF7erVDRbxJUjeKqGAnvELrlzcr+rx+XECgYEAoXLQ\n" +
"MdR+OLsP5XbcoA//Z2pgwwKZVs282MfYjZLVqeEAAC8BB9+8HHrtMaJGvADI06OV\n" +
"7lTCDaE8UlqgzN2B55FmCTiLABjhk3fEDrhGVe4jhEZz1i8t0ArjsYTwXs/uXoUz\n" +
"YP2rcJtkybOQEzjbvM4s5+B8iht+dYaqwoW5/0UCgYAp68UYZlBiXjdoq5dCpuZD\n" +
"gK86ONEw8JrPk4Fvb5EazbFAbGFg3Mta+c+cijMCfy5ljWH3f0U+i8yw1m+QFJLw\n" +
"pKhjx/w8C8gyArdDkQTfG1Ca6nMu71JqZv1Xk/uY4pt37iaHMYxLOc2C5aKv+wA+\n" +
"6OrBVNyWhHcQPp4Hlfjj0QJ/de5oJf4SNV5vPi6U+la1OdV62PgNCls+lxtkFAYu\n" +
"DOlOFtQ+7IGB50vj912STcJE8FOOMYm4NjyQ05df3kXvnjeXUST8ZBXIsO/LRvVU\n" +
"a3CIgRb1hn7v+Af8Sq/Q5XD9rg2eejrSAG+CL9P6ahAecswoATj5v+hVd4PnODB2\n" +
"rQKBgAwe3pkQRFHjameLHip+xcHQ85aASiLjhTvFhFjRHDpJ+FoiJ2H4xi4/jd1F\n" +
"KGrhMpVnLXKwe1HaONFPV3yEFK2da1r66iIr/opcx1hyKmV1xvebcUxYYoRY6j/g\n" +
"JMsceBR10oGEath+43rS78LASIQG83PmTYhkcEkQNftxEGqC\n" +
"-----END RSA PRIVATE KEY-----";
        String privKeyPEM = privateKeyPEM.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
        privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");
       /* byte [] encoded = Base64.decode(privKeyPEM);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
       */
       try {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;
            long nowMs = System.currentTimeMillis()/1000;
            long expMs = nowMs + 3600;
            Date now = new Date(nowMs);
            Date exp = new Date(expMs);       
            byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(privKeyPEM);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
            System.out.println(signingKey);

            JwtBuilder builder = Jwts.builder()
                                        .setIssuedAt(now)
                                        .setSubject(subject)
                                        .setIssuer(issuer)
                                        .setAudience(audience)
                                        .claim("scope",scope)
                                        .signWith(signatureAlgorithm, signingKey)
                                        .setExpiration(exp);         
            return builder.compact();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}

抛出异常说: "必须使用RSA PrivateKey计算RSA签名。 javax.crypto.spec.SecretKeySpec类型的指定键不是RSA PrivateKey。"

提前致谢...

3 个答案:

答案 0 :(得分:1)

您可以使用此库https://github.com/jwtk/jjwt

package <your package name>;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

    public class JWT {

    private String privateKey;
    <your other props such as issuer etc.>

    public JWT(String privateKey) {
        this.privateKey = privateKey;
    }

    public String encode() {

        String retStr = null;

        Claims claims = Jwts.claims();
        claims.put("issuer", "14a2fecb-ddd7-4823-a9cc-67515bc01734");
        claims.put("scope", "signature");
        claims.put("subject", "13f7982d-1f78-46e2-a843-3273568fce89");
        claims.put("audience", "account-d.docusign.com");

        // strip the headers
        privateKey = privateKey.replace("-----BEGIN RSA PRIVATE KEY-----", "");
        privateKey = privateKey.replace("-----END RSA PRIVATE KEY-----", "");
        privateKey = privateKey.replaceAll("\\s+","");

        byte[] encodedKey = android.util.Base64.decode(this.privateKey, android.util.Base64.DEFAULT);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);

        try {

            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey privKey = kf.generatePrivate(keySpec);

            retStr = Jwts.builder().setClaims(claims).signWith(privKey).compact();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return retStr;
    }
}

答案 1 :(得分:0)

如果你们中的一些人仍在努力生成 jwt 令牌,特别是对于 Docusign Auth 服务,也许这个例子也适用于你:

在开始之前,请在 linux 机器上使用此命令以正确格式转换您的 RSA 私钥: 将您的密钥复制并粘贴到文件中并启动:

openssl pkcs8 -topk8 -nocrypt -in privatekeyOLD -out privatekeyNEW

再次复制生成的新密钥后,将代码粘贴到变量 String rsaPrivateKey 中(也许您会删除在复制和粘贴过程中生成的一些额外字符) 作为参考,我使用了这个 https://www.viralpatel.net/java-create-validate-jwt-token/

所需的 JDK 11

import io.jsonwebtoken.Jwts;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

public class JWTIO{
//  reference https://www.viralpatel.net/java-create-validate-jwt-token/
public static String createJwtSignedHMAC() throws InvalidKeySpecException, NoSuchAlgorithmException {

    PrivateKey privateKey = getPrivateKey();

    Instant now = Instant.now();
    String jwtToken = Jwts.builder()     
            .setIssuer("2a03dbc6-XXXX-XXXXX-XXXX-7e9ac9df613f")
            .setSubject("2a285ff3-XXXX-XXXX-XXXXX-e433497afc23")
            .setAudience("account-d.docusign.com")
            .claim("scope","signature impersonation")
            .setIssuedAt(Date.from(now))
            .setExpiration(Date.from(now.plus(5l, ChronoUnit.MINUTES)))
            .signWith(privateKey)
            .compact();

    return jwtToken;
}

private static PrivateKey getPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
    /* before to put the rsa private key in your String you must convert in PKCSS#8 
     * THE CERTIFICATE PROVIDED BY DOCUSIGN IS PKCS#1 and does not works
     * copy the rsa provate key ina file and use this command in linux ubuntu for 
     * example
     * openssl pkcs8 -topk8 -nocrypt -in privatekeyOLD -out privatekeyNEW
     * */
    String rsaPrivateKey = "-----BEGIN PRIVATE KEY-----" + 
            "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCKAIc+hqdKgcPb" + 
            "9XbR5Osbdeq1J14zxRG58CkrHZO0PMSf/smoCEyEcxhGsjrITl/sLv/q8iOVMKgY" + 
            "KdpOMIoPDGCF8KCXA4F9hM/WXJstprEeqPi7a1FnXzi3uwaf+jy2zUviDt09jm+g" + 
            "uu5TaZzTuzyoClEgfwIu2LwuHaJKtjceRKHWKvUqqxBQMXlq/s5lNXWajWSpLffP" + 
            "/5L0YfCK9uW1FJJXT4cP9fiNbcd6GiHGwVk/eJy4QYaR9lWNvnKKu1H52xgWkLC+" + 
            "TwfOtcqtjF9sWE5XIAjpdFVh5u64g/uOafKzEF/yVOTzPvYUWI3PhKjqSS3V3yhk" + 
            "TqoFG53hAgMBAAECggEALo0NEgdkCRsK0XjUsurQb/vvx1nXSglQ+HLNwFCC0Yqq" + 
            "HPpaVccu4ILejoJyl7zwWIBmLX+uhxXZrgT4MeXnvDnFmYjY8vfox0l0vm+QnO6c" + 
            "0qXW+Ymy9PbG8BszmeVUc6l+zmuLL8eLWiGUYSjAESAYzupkAV02hEzx9XBjnWWl" + 
            "ifoWOXvO22ADtO8jRk1ODbOrqyt1Hz7UDLtQI6Vdw3QovadW/3hKCx+0a/WxgDhR" + 
            "VosPudbzIGYBzdnbOyT+ToVIyMBTJU/8muZbWsaaOXHhel9lD/CUjvCcivL5tcSU" + 
            "0KvEiHVCXWfojbuy/RksgSTvl/aFEOrmqRjyu2JEbQKBgQDt+B4r6NVuqOPus+Xb" + 
            "RHF8QpvtwzIWSxxAwbtAWxWDJSrMMlhAx1yZ4kefSxbxAkdNkv9vQoVabVAEiWdJ" + 
            "VzXB8W9tvcD57zrbiraHQI5hCn+t5GIsSTnbhg6CG2dxv58uWviDneeNEdDeki+b" + 
            "vwTTXuHIeyCnPdLI/vaMzO0clwKBgQCUdVm5IYxRd93ohYH14zIfty+7J301iB3t" + 
            "t/fccrg1qjx4WniLbhLweVYdL44XpzMZUzdAYFhyHUIyAWIR4yHC3b0+u34oshjv" + 
            "MD/gjWPiNTBBthYTy559todm3jyj+g9Z+gLLu2G93+wGl3u15igiTy0oMmh4bS3s" + 
            "xtFk1pLQRwKBgF8L+wEOvjC0xFVTBTvO2oUHFcChdh/xYBd9SY0q1CzNa4qjkRxO" + 
            "hG3yMykslL0ua8xQKjYGG71Ca/Nj7h0c+Bu+kwMCB1HMe3W0sbLT1gpsZxLNZWjK" + 
            "1pEXujO9PlPwdWPOcfQf3Zw6wXIkcV+DrCnAe+3XP/OMfeRJ8a/LKemBAoGAf46M" + 
            "9wqiO+WYH4+G6LS7fpCxTEdTx8kangQxzZIsQL/ykR568KI1V7WJji4sEpqwxxO/" + 
            "J2sg03vcQob5spDLk1lenyYN8f2Eew+j8tbJebVlrzA6q+uKVE2e7X4J8IKM6ixs" + 
            "doycIL7jV46U1ufYmBIbpKwbI0375bO2esP7BUUCgYBqmx7GJnyOapOYlR7wHhYL" + 
            "rXk0QWwE7j3d4zQCHGOqzFqWxyIi1hsQYCwgOeobmd0r5kULRRptYBKvflEiboVq" + 
            "RL3VeyR9ZIEDkbCUewwf2qn6EoOCfi7x6/36brhn8r3mWC9rvNiKB33iBJrkin1p" + 
            "f0aUgyrlhk1aMnDDBFFb8A==" + 
            "-----END PRIVATE KEY-----";

    rsaPrivateKey = rsaPrivateKey.replace("-----BEGIN PRIVATE KEY-----", "");
    rsaPrivateKey = rsaPrivateKey.replace("-----END PRIVATE KEY-----", "");

    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(rsaPrivateKey));
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey privKey = kf.generatePrivate(keySpec);
    return privKey;
}
}

所需的库

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>

要调用这个方法,你必须用 try catch 包围它,然后你就可以开始了 示例:

String bearer = null;
try {
    bearer = JWTIO.createJwtSignedHMAC();
} catch (InvalidKeySpecException e) {
    
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {

    e.printStackTrace();
}

答案 2 :(得分:0)

由于行分隔符,它不起作用。您还应该删除 \n by

PT_DYNAMIC

之后

privKeyPEM = privKeyPEM.replaceAll("\n", "");