JWT几乎是当前分布式开发中无状态token的最佳选择,被越来越多的开发者接受和使用, JWT
是基于加密算法的认证方式,省去了到认证服务器的校验过程,认证效率大大提高。更详细的关于JWT的介绍可以点击 这里查看。
通常大家在使用JWT的时候都是使用 HmacSHA256
加密钥的加密方式,这种方式严格依赖密钥,在分布式开发的过程中,通常是由认证服务器生成 JWT
,然后再由资源校验 JWT
的有效性,那么这时候资源服务器就也需要密钥了,认证服务和资源服务很可能是不同的团队开发和维护,密钥在这个过程中传递,很有可能泄漏。密钥一旦泄漏,对方就可以轻易的模拟一个 JWT
token出来,获取相关信息。
RSA非对称加密算法就可以很好的解决这个问题,认证服务器使用私钥生成 JWT
,资源服务器使用公钥去校验 JWT
,认证服务去管理私钥,公钥开放给各个资源服务,这样密钥泄漏的可能性就大大降低了。
首先生成公钥和密钥
-
打开终端 Terminal
或者 iTerm
输入以下命令生成私钥:
1 | openssl genrsa -out rsa_private_key.pem 1024 |
-
把RSA私钥转换成PKCS8格式
1 | openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt |
注意把控制台输出的私钥内容替换到私钥文件( rsa_private_key.pem
)中去。
-
生成公钥
1 | openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout |
我这里生成了一份公钥和私钥,用于测试:
私钥 rsa_private_key.pem
:
rsa_private_key.pem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANDrROfXcbDeMB40 Aa+X/JkRquSj2hXfeMAbkiArzobMEkqwDbdG76/YtSRx6Nem79yqwhUNqNg+lKfM RMprERDm/+/eX1Tv3YDFzpXZay0md5hZxUQKNqWDobCd7U8twKRDfIw1BfIBtPid L3RKmOXlJudoa+KeThIRQlT2DHrFAgMBAAECgYBs1OKEU7sqA9TVJwppyqcPpiB8 Es8c7dkdWj94+tkPZ2dv+N5sR0u9MwrJ/XzqOlBhh6KrDP6UB6Ww87wyJiwwy+11 R6Oz2XxPSGBFimoZPyc+dgPC/z63PPpHStXN9027IcaS47sjvtUp6HoCjLZZNht/ oSGxSLZjLDXPm3JLgQJBAP2MAgP387fF8wa5WHqafaNGKW5KI9srwY7szCbleO0Q EL5eLmYVGUns5sjRFJSjl242QWvkmNlp52TgIkfj+M0CQQDS8LnGa5zeWSzUiDkP oiMhaJSVQtlgApfsTAA7Lx+M0TENjJcFGFKhGWDSY8AIE1DzYWIijRbC0vsc+WZZ zOnZAkEA1dt3/7zudv2iJPPEq3UPr94IKByk7cKUemdFMzGus9YvKULrQ/Nb5zzI 1G12PIFXwwBEYirouclYAYADqjuhqQJAHfgDfNRHKjPjMaLU8IqpkRKJoZcoyQI1 UWYO1lnAksIZxQIHZrro6mhvoBR58OvFoX5hceU3qaBN+vTX/MQnKQJBAKX95ga2 NNWQ5Y1TfMEN3X0Ki+y9H64HODxaIuHW/h0W7kVssHSdNPvlEzR+S5pBaVy/6nDH CUXtz5Uuq3Wm3CA= -----END PRIVATE KEY---- |
公钥 rsa_public_key.pem
:
rsa_public_key.pem
1 2 3 4 5 6 7 | -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ60Tn13Gw3jAeNAGvl/yZEark o9oV33jAG5IgK86GzBJKsA23Ru+v2LUkcejXpu/cqsIVDajYPpSnzETKaxEQ5v/v 3l9U792Axc6V2WstJneYWcVECjalg6Gwne1PLcCkQ3yMNQXyAbT4nS90Spjl5Sbn aGvink4SEUJU9gx6xQIDAQAB -----END PUBLIC KEY----- |
然后开始生成JWT
Java开发中一般使用 jjwt这个库来操作 JWT
,在 build.gradle
用添加如下依赖即可:
build.gradle
1 2 3 | dependencies { compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0' } |
生成
生成 JWT
的时候需要把签名算法改在 RS256
,这一点很重要,这里就表明要求 JWT
使用 RSA
算法进行加密:
JwtUtils.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public static String buildJwtRS256() throws Exception { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256; // 读取私钥 String key = readResourceKey("rsa_private_key.pem"); // 生成签名密钥 byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(key); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") .setIssuer("marco") .setSubject("token") .signWith(signatureAlgorithm, privateKey); // jwt中需要传递的内容 builder.claim("id", 10001); return builder.compact(); } |
生成的 JWT
字符串如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJtYXJjbyIsInN1YiI6InRva2VuIiwiaWQiOjEwMDAxfQ.KmPbzze6zGq5dXDt_XBmwGDsRljHC1dDda5vDroBaJCMdojKczyCUuBYQ203WY7WvgofFnmDw8t2APncDthdEbOxZ2lLXZeiadY6DnSVzOierTzehXGLq7jjONif5I_1vnyrkL5D6EQ2c7RrQNQZmkYGu_pSTkifC9bHJrlKMTs
解析
使用 RSA
公钥解析 JWT
代码如下:
JwtUtils.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public static Claims parseJwtRS256(String jwt) { Claims claims = null; try { // 读取公钥 String key = readResourceKey("rsa_public_key.pem"); // 生成签名公钥 byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(key); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(keySpec); claims = Jwts.parser() .setSigningKey(publicKey) .parseClaimsJws(jwt).getBody(); } catch (Exception e) { e.printStackTrace(); } return claims; } |
本篇博文代码地址: https://github.com/MTequila/demos/tree/master/jwt-rsa