若依(RuoYi)SpringBoot框架密码加密传输(前后分离板)

运行环境:

Java 版本 1.8

Spring Boot 版本: 2.2.13.RELEASE


目前登录接口密码是明文传输 为了更高安全性 我准备调整为加密方式传输( 这里选择Rsa加密算法) 并分享下编写过程

更改前

 更改后

 

大概加密流程:

  1. 后台生成随机公钥私钥
  2. 前台拿到公钥 集成jsencrypt实现密码加密
  3. 传输加密后的密码给后台
  4. 后台通过私钥对加密后的密码进行解密

若依详细登陆流程<<<可以看这里

若依官方的加密方法<<<原本是固定公私秘钥 我改为了随机生成

篇幅过长『请』耐心看完哦😋 有什么问题可以联系我~

目录

运行环境:

大概加密流程:

后台改动

首先新建RsaUtils类

在controller层添加获取公钥接口

登录方法SysLoginService类修改(重点)

重置密码接口要也需要更改!!不要忘记啦

最后在SecurityConfig类里添加白名单

前端改动

login.js添加获取公钥接口路径

user.js更改登陆方法

resetPwd.vue更改修改密码的页面

JSEncrypt.js更改加解密方法


后台改动

首先新建RsaUtils类

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

@Component
public class RsaUtils {
    // Rsa 私钥 也可固定秘钥对 若依原写法(不安全)
    public static String privateKeys = "";
    private static String publicKeyStr = "";
    private static String privateKeyStr = "";
    private static final RsaKeyPair rsaKeyPair = new RsaKeyPair();
    private static final Logger logger = LoggerFactory.getLogger(MapUtils.class);

    /**
     * 私钥解密
     *
     * @param text 待解密的文本
     * @return 解密后的文本
     */
    public static String decryptByPrivateKey(String text) throws Exception {
//        logger.info(rsaKeyPair.getPrivateKey());
        return decryptByPrivateKey(rsaKeyPair.getPrivateKey(), text);
    }

    /**
     * 公钥解密
     *
     * @param publicKeyString 公钥
     * @param text            待解密的信息
     * @return 解密后的文本
     */
    public static String decryptByPublicKey(String publicKeyString, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        byte[] result = cipher.doFinal(Base64.decodeBase64(text));
        return new String(result);
    }

    /**
     * 私钥加密
     *
     * @param privateKeyString 私钥
     * @param text             待加密的信息
     * @return 加密后的文本
     */
    public static String encryptByPrivateKey(String privateKeyString, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(text.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * 私钥解密
     *
     * @param privateKeyString 私钥
     * @param text             待解密的文本
     * @return 解密后的文本
     */
    public static String decryptByPrivateKey(String privateKeyString, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(Base64.decodeBase64(text));
        return new String(result);
    }

    /**
     * 公钥加密
     *
     * @param publicKeyString 公钥
     * @param text            待加密的文本
     * @return 加密后的文本
     */
    public static String encryptByPublicKey(String publicKeyString, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] result = cipher.doFinal(text.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * 构建RSA密钥对
     *
     * @return 生成后的公私钥信息
     */
    @Bean
    public void generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
        String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        rsaKeyPair.setPrivateKey(privateKeyString);
        rsaKeyPair.setPublicKey(publicKeyString);
        publicKeyStr = publicKeyString;
        privateKeyStr = privateKeyString;
    }


    public static String getPublicKey() {
        return publicKeyStr;
    }

    public static String getPrivateKey() {
        return privateKeyStr;
    }

    public static RsaKeyPair rsaKeyPair() {
        return rsaKeyPair;
    }

    /**
     * RSA密钥对对象
     */
    public static class RsaKeyPair {
        private String publicKey;
        private String privateKey;

        public void setPublicKey(String publicKey) {
            this.publicKey = publicKey;
        }

        public void setPrivateKey(String privateKey) {
            this.privateKey = privateKey;
        }

        public RsaKeyPair() {

        }

        public RsaKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }
    }
}
 

RsaUtils添加了@Component注解 generateKeyPair()构建密钥对添加了@Bean注解 在项目启动时通过@Bean的方式将普通类事例化到spring容器中 所以在系统启动后 每次调用接口会是一样的公私秘钥 每次重启后公私钥不同

在controller层添加获取公钥接口

    /**
     * 获取公钥 前端用来密码加密
     *
     * @return
     */
    @GetMapping("/publicKey")
    public RsaUtils.RsaKeyPair publicKey() {
        //便于测试 公私秘钥都传了 可改为只传公钥
        //RsaUtils.RsaKeyPair rsaKeyPair = new RsaUtils.RsaKeyPair();
        //rsaKeyPair.setPublicKey(RsaUtils.getPublicKey());
        //return rsaKeyPair;
        return RsaUtils.rsaKeyPair();
    }

登录方法SysLoginService类修改(重点)

测试内部会调用authenticationManager.authenticate()对账号和密码做验证 具体细节推荐看原代码

最终会调用UserDetailsServiceImpl.loadUserByUsername()方法 若依重写了此方法

authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, RsaUtils.decryptByPrivateKey(password)));

重置密码接口要也需要更改!!不要忘记啦

   /**
     * 重置密码
     */
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
    public AjaxResult updatePwd(String oldPassword, String newPassword) throws Exception {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        String userName = loginUser.getUsername();
        //加密后的
        String password = loginUser.getPassword();
        //解密
        oldPassword = RsaUtils.decryptByPrivateKey(oldPassword);
        newPassword = RsaUtils.decryptByPrivateKey(newPassword);
        //拿原密码和加密后的解密
        if (!SecurityUtils.matchesPassword(oldPassword, password)) {
            return AjaxResult.error("修改密码失败,旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, password)) {
            return AjaxResult.error("新密码不能与旧密码相同");
        }
        if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) {
            // 更新缓存用户密码
            loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
            tokenService.setLoginUser(loginUser);
            return AjaxResult.success();
        }
        return AjaxResult.error("修改密码异常,请联系管理员");
    }

最后在SecurityConfig类里添加白名单

/**
  * anonymous() 允许匿名用户访问,不允许已登入用户访问
  * permitAll() 不管登入,不登入 都能访问
  */
  .antMatchers("/publicKey").permitAll()

anonymous()和permitAll()权限是个坑 大家注意

至此后台工作已完成 挪步前端(没错 前后端都是我写的😭)

前端改动

login.js添加获取公钥接口路径

// 获取key
export function getPublicKey() {
  return request({
    url: '/publicKey',
    method: 'get',
  })
}

user.js更改登陆方法

actions: {
    getPublicKey() {
      return new Promise((resolve, reject) => {
        getPublicKey()
          .then(res => {
            resolve(res)
          })
          .catch(error => {
            reject(error)
          })
      })
    },
    // 登录
    Login({ commit, dispatch }, userInfo) {
      return new Promise((resolve, reject) => {
        dispatch('getPublicKey').then(res => {
          let publicKey = res.publicKey
          const username = userInfo.username.trim()
          //调用加密方法(传密码和公钥)
          const password = encrypt(userInfo.password, publicKey)
          const code = userInfo.code
          const uuid = userInfo.uuid
          login(username, password, code, uuid)
            .then(res => {
              setToken(res.token)
              commit('SET_TOKEN', res.token)
              resolve()
            })
            .catch(error => {
              reject(error)
            })
          })
      })
    },

resetPwd.vue更改修改密码的页面

methods: {
    getPublicKey() {
      return new Promise((resolve, reject) => {
        getPublicKey()
          .then(res => {
            resolve(res)
          })
          .catch(error => {
            reject(error)
          })
      })
    },
      submit() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          this.getPublicKey().then(res=>{
            let publicKey = res.publicKey
            console.log("res.publicKey",res.publicKey)
            const oldPassword = encrypt(this.user.oldPassword, publicKey)
            const newPassword = encrypt(this.user.newPassword, publicKey)
            updateUserPwd(oldPassword, newPassword).then(
              response => {
                this.msgSuccess("修改成功");
              }
            );
          })

        }
      });
    },
    close() {
      this.$store.dispatch("tagsView/delView", this.$route);
      this.$router.push({ path: "/index" });
    }
  }

JSEncrypt.js更改加解密方法

import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'

// 密钥对生成 http://web.chacuo.net/netrsakeypair

//这里注掉了原来固定的公私钥
//const publicKey = ''
//const privateKey = ''

// 加密
export function encrypt(txt, publicKey) {
  const encryptor = new JSEncrypt()
  encryptor.setPublicKey(publicKey) // 设置公钥
  return encryptor.encrypt(txt) // 对数据
}

// 解密(暂无使用)
export function decrypt(txt) {
  const encryptor = new JSEncrypt()
  encryptor.setPrivateKey(privateKey) // 设置私钥
  return encryptor.decrypt(txt) // 对数据进行解密
}

登陆验证下吧~

有问题欢迎留言讨论😋

  • 22
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 29
    评论
若按照RuoYi框架进行前后端分离,你需要进行以下步骤: 1. 创建前端项目:首先,你需要创建一个前端项目,可以选择使用Vue.js、React.js或Angular等框架进行开发。 2. 配置前端项目:在前端项目中,你需要配置相关的路由、页面组件以及与后端接口通信的方法。可以使用axios或fetch等工具发送HTTP请求。 3. 定义接口规范:在后端项目中,你需要定义接口的URL路径、请求方式、请求参数以及返回数据的格式。 4. 实现后端接口:根据前端定义的接口规范,在后端项目中实现对应的接口逻辑。可以使用RuoYi提供的注解和工具类简化开发过程。 5. 跨域配置:由于前后端分离的架构,前端项目和后端项目可能存在跨域请求的问题。你需要在后端配置跨域访问权限,确保前端可以正常调用后端接口。 6. 接口测试与调试:完成前后端开发和配置后,你可以通过Postman或浏览器等工具进行接口测试和调试,确保数据的正常传输和交互。 7. 部署与运行:最后,你可以将前端项目打包成静态文件,并将其部署到Web服务器上。同时,将后端项目部署到应用服务器上,启动应用程序。 这样,你就成功实现了RuoYi框架的前后端分离。前端负责展示和用户交互,后端负责处理业务逻辑和数据存储。通过接口的方式进行通信,实现了前后端的解耦和独立开发
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜の雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值