当前位置:   article > 正文

JWT+RSA鉴权_jwt rsa

jwt rsa

目录

1、JWT

1.1 JWT简介

1.2 JWT数据格式  

2、 登录和鉴权流程:JWT+HS256算法

3、RSA非对称加密

  4、 登录和鉴权流程:JWT+RSA

4.1 RSA工具类

4.2 JWT工具类

1、JWT

1.1 JWT简介

JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;官网:JSON Web Tokens - jwt.io (JWT,生成Token加密字符串的一个标准或格式!)

GitHub上jwt的java客户端:https://github.com/jwtk/jjwt

1.2 JWT数据格式  

JWT包含三部分数据:

  • Header:头部,通常头部有两部分信息:

    • 声明类型,这里是JWT

    • 签名算法,自定义

    我们会对头部进行base64编码,得到第一部分数据

    如图所示:头部是不具备安全性的。

    Payload:载荷,就是有效数据,一般包含下面信息:

  • 用户身份信息(注意,这里因为采用base64加密,可解密,因此不要存放敏感信息)

  • tokenID:当前这个JWT的唯一标示

  • 注册声明:如token的签发时间,过期时间,签发人等

  • 这部分也会采用base64加密,得到第二部分数据

    如图所示:载荷也不具备安全性。

  • Signature:签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥(secret)(不要泄漏,最好周期性更换),通过加密算法生成。用于验证整个数据完整和可靠性

2、 登录和鉴权流程:JWT+HS256算法

3、RSA非对称加密

  • 对称加密,如AES

    • 基本原理:将明文分成N个组,然后使用密钥对各个组进行加密,形成各自的密文,最后把所有的分组密文进行合并,形成最终的密文。

    • 优势:算法公开、计算量小、加密速度快、加密效率高

    • 缺陷:双方都使用同样密钥,安全性得不到保证

  • 非对称加密,如RSA

    • 基本原理:同时生成两把密钥:私钥和公钥,私钥隐秘保存,公钥可以下发给信任客户端

    • 私钥加密,持有私钥或公钥才可以解密

    • 公钥加密,持有私钥才可解密

    • 优点:安全,难以破解

    • 缺点:算法比较耗时

不可逆加密,如MD5,SHA,HS加密

  • 基本原理:加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,无法根据密文推算出明文。

  4、 登录和鉴权流程:JWT+RSA

有了非对称加密,我们就可以改变签名和验签的方式了:

  • 生成RSA密钥对,私钥存放在授权中心,公钥下发给微服务

  • 在授权中心利用私钥对JWT签名

  • 在微服务利用公钥验证签名有效性

因为非对称加密的特性,不用担心公钥泄漏问题,因为公钥是无法伪造签名的,但要确保私钥的安全和隐秘

非对称加密后的授权和鉴权流程:

4.1 RSA工具类

  1. public class RsaUtils {
  2. private static final int DEFAULT_KEY_SIZE = 2048;
  3. /**
  4. * 从文件中读取公钥
  5. *
  6. * @param filename 公钥保存路径,相对于classpath
  7. * @return 公钥对象
  8. * @throws Exception
  9. */
  10. public static PublicKey getPublicKey(String filename) throws Exception {
  11. byte[] bytes = readFile(filename);
  12. return getPublicKey(bytes);
  13. }
  14. /**
  15. * 从文件中读取密钥
  16. *
  17. * @param filename 私钥保存路径,相对于classpath
  18. * @return 私钥对象
  19. * @throws Exception
  20. */
  21. public static PrivateKey getPrivateKey(String filename) throws Exception {
  22. byte[] bytes = readFile(filename);
  23. return getPrivateKey(bytes);
  24. }
  25. /**
  26. * 获取公钥
  27. *
  28. * @param bytes 公钥的字节形式
  29. * @return
  30. * @throws Exception
  31. */
  32. private static PublicKey getPublicKey(byte[] bytes) throws Exception {
  33. bytes = Base64.getDecoder().decode(bytes);
  34. X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
  35. KeyFactory factory = KeyFactory.getInstance("RSA");
  36. return factory.generatePublic(spec);
  37. }
  38. /**
  39. * 获取密钥
  40. *
  41. * @param bytes 私钥的字节形式
  42. * @return
  43. * @throws Exception
  44. */
  45. private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
  46. bytes = Base64.getDecoder().decode(bytes);
  47. PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
  48. KeyFactory factory = KeyFactory.getInstance("RSA");
  49. return factory.generatePrivate(spec);
  50. }
  51. /**
  52. * 根据密文,生存rsa公钥和私钥,并写入指定文件
  53. *
  54. * @param publicKeyFilename 公钥文件路径
  55. * @param privateKeyFilename 私钥文件路径
  56. * @param secret 生成密钥的密文
  57. */
  58. public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret, int keySize) throws Exception {
  59. KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
  60. SecureRandom secureRandom = new SecureRandom(secret.getBytes());
  61. keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);
  62. KeyPair keyPair = keyPairGenerator.genKeyPair();
  63. // 获取公钥并写出
  64. byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
  65. publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);
  66. writeFile(publicKeyFilename, publicKeyBytes);
  67. // 获取私钥并写出
  68. byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
  69. privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);
  70. writeFile(privateKeyFilename, privateKeyBytes);
  71. }
  72. private static byte[] readFile(String fileName) throws Exception {
  73. return Files.readAllBytes(new File(fileName).toPath());
  74. }
  75. private static void writeFile(String destPath, byte[] bytes) throws IOException {
  76. File dest = new File(destPath);
  77. if (!dest.exists()) {
  78. dest.createNewFile();
  79. }
  80. Files.write(dest.toPath(), bytes);
  81. }
  82. }

4.2 JWT工具类

  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt-api</artifactId>
  4. <version>0.10.5</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>io.jsonwebtoken</groupId>
  8. <artifactId>jjwt-impl</artifactId>
  9. <version>0.10.5</version>
  10. <scope>runtime</scope>
  11. </dependency>
  12. <dependency>
  13. <groupId>io.jsonwebtoken</groupId>
  14. <artifactId>jjwt-jackson</artifactId>
  15. <version>0.10.5</version>
  16. <scope>runtime</scope>
  17. </dependency>

JWT中,会保存载荷数据,我们计划存储3部分:

  • id:jwt的id

  • 用户信息:用户数据,不确定,可以是任意类型

  • 过期时间:Date

为了方便后期获取,我们定义一个类来封装

  1. @Data
  2. public class Payload<T> {
  3. private String id;
  4. private T info;
  5. private Date expiration;
  6. }

封装用户信息类:UserInfo

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class UserInfo {
  5. private Long id;//用户ID
  6. private String username;//用户名称
  7. private String role;//用户角色
  8. }

JWT工具

  1. public class JwtUtils {
  2. private static final String JWT_PAYLOAD_USER_KEY = "user";
  3. /**
  4. * 私钥加密token
  5. *
  6. * @param info 载荷中的数据
  7. * @param privateKey 私钥
  8. * @param expire 过期时间,单位分钟
  9. * @return JWT
  10. */
  11. public static String generateTokenExpireInMinutes(Object info, PrivateKey privateKey, int expire) {
  12. return Jwts.builder()
  13. //claim: 往Jwt的载荷存入数据
  14. .claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(info))
  15. //往Jwt的载荷存入数据,设置固定id的key
  16. .setId(createJTI())
  17. //往Jwt的载荷存入数据,设置固定exp的key
  18. .setExpiration(DateTime.now().plusMinutes(expire).toDate())
  19. //设置token的签名
  20. .signWith(privateKey, SignatureAlgorithm.RS256)
  21. .compact();
  22. }
  23. /**
  24. * 私钥加密token
  25. *
  26. * @param info 载荷中的数据
  27. * @param privateKey 私钥
  28. * @param expire 过期时间,单位秒
  29. * @return JWT
  30. */
  31. public static String generateTokenExpireInSeconds(Object info, PrivateKey privateKey, int expire) {
  32. return Jwts.builder()
  33. .claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(info))
  34. .setId(createJTI())
  35. .setExpiration(DateTime.now().plusSeconds(expire).toDate())
  36. .signWith(privateKey, SignatureAlgorithm.RS256)
  37. .compact();
  38. }
  39. /**
  40. * 公钥解析token
  41. *
  42. * @param token 用户请求中的token
  43. * @param publicKey 公钥
  44. * @return Jws<Claims>
  45. */
  46. private static Jws<Claims> parserToken(String token, PublicKey publicKey) {
  47. return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
  48. }
  49. private static String createJTI() {
  50. return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
  51. }
  52. /**
  53. * 获取token中的用户信息
  54. *
  55. * @param token 用户请求中的令牌
  56. * @param publicKey 公钥
  57. * @return 用户信息
  58. */
  59. public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> userType) {
  60. Jws<Claims> claimsJws = parserToken(token, publicKey);
  61. Claims body = claimsJws.getBody();
  62. Payload<T> claims = new Payload<>();
  63. claims.setId(body.getId());
  64. claims.setInfo(JsonUtils.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType));
  65. claims.setExpiration(body.getExpiration());
  66. return claims;
  67. }
  68. /**
  69. * 获取token中的载荷信息
  70. *
  71. * @param token 用户请求中的令牌
  72. * @param publicKey 公钥
  73. * @return 用户信息
  74. */
  75. public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) {
  76. Jws<Claims> claimsJws = parserToken(token, publicKey);
  77. Claims body = claimsJws.getBody();
  78. Payload<T> claims = new Payload<>();
  79. claims.setId(body.getId());
  80. claims.setExpiration(body.getExpiration());
  81. return claims;
  82. }
  83. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/989922
推荐阅读
相关标签
  

闽ICP备14008679号