• 前后端分离 RSA 加密登录流程(记录)


    技术栈

    前端:VUE + Element-Ui
    后端:SpringBoot

    流程

    公匙加密、私匙解密

    前端流程

    1. 调用接口获取rsa公匙
    2. 登录时携带rsa公匙 和 JSEncrypt加密后的rsa密码
    3. 登录验证失败重新获取公匙
    4. 登录成功时 后端会返回token,在以后的请求中 请求头携带该token进行访问

    后端流程

    1. 编写返回公匙的接口,返回前 存入redis key:公匙 value:私匙
    2. 登录接口中根据公匙从redis获取私匙进行解密 密码
    3. 密码等校验通过后,生成token、存入redis 返回给前端
    4. 后端配置过滤器,过滤其它接口请求,验证token的有效性

    前后端 rsa 加密与解密

    前端加密

    1. 安装插件jsencrypt

      npm install jsencrypt
      
      • 1
    2. 登录页面引入

      import {JSEncrypt} from 'jsencrypt'
      
      • 1
    3. 加密

      	// 新建JSEncrypt对象
          let encrypt = new JSEncrypt()
          	// 公钥加密
            encrypt.setPublicKey(loginParams.rsaPublicKey)
            let passwordEncrpt = encrypt.encrypt(values.password)
      
      • 1
      • 2
      • 3
      • 4
      • 5

    后端对应功能

    1. 导入 hutool 工具包

    	<dependency>
               <groupId>cn.hutoolgroupId>
               <artifactId>hutool-allartifactId>
               <version>5.3.8version>
           dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 返回公匙

    	@ApiOperation("获取RSA公钥")
        @GetMapping("/getRSAPublicKey")
        public Result<String> getRSAPublicKey() {
            RSA rsa = new RSA();
            // 私匙
            String privateKeyBase64 = rsa.getPrivateKeyBase64();
            // 公匙
            String publicKeyBase64 = rsa.getPublicKeyBase64();
            //存到redis key为公钥 value为私钥
            redisUtil.set(publicKeyBase64, privateKeyBase64, 300L);
            
            return Result.message(publicKeyBase64);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3. 解密

    1. JWT工具类
      
      public class JWTUtils {
      
          /**
           * 生成token,一小时后过期
           * @param username 用户名
           * @param secret 秘钥
           * @return
           */
          public static String sign(String username,String secret) {
              // 创建 token
              String token = JWT.create()
                      // 数据(也就是 payload 负载)
                      .withClaim("username", username)
                      //过期时间 1小时
                      .withExpiresAt(DateUtil.offsetHour(new Date(),1))
                      // 设置秘钥
                      .sign(Algorithm.HMAC256(secret));
              return token;
          }
      
          /**
           * 解密token
           * @param token
           * @throws Exception
           * @return
           */
          public static DecodedJWT decoded(String token){
              DecodedJWT decode = null;
              try {
                  decode = JWT.decode(token);
              }catch (JWTDecodeException e){
                  return null;
              }
              return decode;
          }
      
          /**
           * 根据request中的token获取用户账号
           *
           * @param request
           * @return
           */
          public static String getUserNameByToken(HttpServletRequest request) throws Exception {
              String accessToken = request.getHeader("X-Access-Token");
              String username = getUserNameByToken(accessToken);
              if (!StringUtils.hasLength(username)) {
                  throw new Exception("未获取到用户");
              }
              return username;
          }
      
          /**
           * 获得token中的信息无需secret解密也能获得
           *
           * @return token中包含的用户名
           */
          public static String getUserNameByToken(String token) {
              try {
                  DecodedJWT jwt = JWT.decode(token);
                  return jwt.getClaim("username").asString();
              } catch (JWTDecodeException e) {
                  return null;
              }
          }
      
      
          /**
           * 校验token是否正确
           *
           * @param token  密钥
           * @param secret 用户的密码
           * @return 是否正确
           */
          public static boolean verify(String token, String username, String secret) {
              try {
                  // 根据密码生成JWT效验器
                  DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret))
                          .withClaim("username", username)
                          .build()
                          .verify(token);
                  // 效验TOKEN
                  return true;
              } catch (Exception exception) {
                  return false;
              }
          }
          
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
    2. 生成公匙
        @GetMapping("/getPublicKey")
        public String getPublicKey(){
            RSA rsa = new RSA();
            redisUtil.set(rsa.getPublicKeyBase64(),rsa.getPrivateKeyBase64(),300L);
            return rsa.getPublicKeyBase64();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 解密与获取token
      	// 根据公匙 从redis中获取 私匙
      	String rsaPrivateKey = String.valueOf(redisUtil.get(rsaPublicKey));
      	RSA rsa = new RSA(rsaPrivateKey, rsaPublicKey);
      	// 解密
          byte[] decrypt = rsa.decrypt(str, KeyType.PrivateKey);
          String password = new String(decrypt);
          // 生成token
          String token = JWTUtils.sign(username, "签名");
          // 将token存入redis
      	redisUtil.set("user_"+username,token);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
  • 相关阅读:
    Spring IOC容器的这些扩展点你都了解吗?
    第三方渠道管控,服务商能为您做什么
    常见8种数据结构
    VS使用ImageMagick++库建立图像
    数据结构与算法之Hash&BitMap
    MySQL中存储引擎之间的对比
    操作系统-内存管理
    05【NIO核心组件之Channel】
    Python游戏嗷大喵快跑设计
    c++ SFML 获取ftp某个目录下所有的文件或者文件夹
  • 原文地址:https://blog.csdn.net/weixin_45947759/article/details/125871607