ruoyi-vue框架密码加密传输

先看一下改造后的样子,输入的密码不会再以明文展示。

下面我主要把前后端改造的代码贴出来。

1.后端代码

RsaUtils类

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

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(RsaUtils.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 生成后的公私钥信息*/@Beanpublic 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;}}
}

在SysLoginController添加获取公钥接口

/*** 获取公钥 前端用来密码加密** @return*/@GetMapping("/publicKey")public RsaUtils.RsaKeyPair publicKey() {return RsaUtils.rsaKeyPair();}

修改SysLoginService类中的login方法

/*** 登录验证** @param username 用户名* @param password 密码* @param code 验证码* @param uuid 唯一标识* @return 结果*/public String login(String username, String password, String code, String uuid){// 验证码校验validateCaptcha(username, code, uuid);// 登录前置校验loginPreCheck(username, password);// 用户验证Authentication authentication = null;try{//RsaUtils.decryptByPrivateKey(password)解密密码UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,  RsaUtils.decryptByPrivateKey(password));AuthenticationContextHolder.setContext(authenticationToken);// 该方法会去调用UserDetailsServiceImpl.loadUserByUsernameauthentication = authenticationManager.authenticate(authenticationToken);}catch (Exception e){if (e instanceof BadCredentialsException){AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));throw new UserPasswordNotMatchException();}else{AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));throw new ServiceException(e.getMessage());}}finally{AuthenticationContextHolder.clearContext();}AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));LoginUser loginUser = (LoginUser) authentication.getPrincipal();recordLoginInfo(loginUser.getUserId());// 生成tokenreturn tokenService.createToken(loginUser);}

修改重置密码

/*** 重置密码*/@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中添加获取公钥接口

因为密码校验时会校验长度,加密后的密码会超出框架内原来设定的长度,修改UserConstants类中的PASSWORD_MAX_LENGTH

2.前端代码变动

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) // 对数据进行解密
}

login.js添加获取公钥路由

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

user.js修改登入方法,方便copy我直接全放进来了

import { login, logout, getInfo,getPublicKey } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { encrypt, decrypt } from '@/utils/jsencrypt'const user = {state: {token: getToken(),id: '',name: '',avatar: '',roles: [],permissions: []},mutations: {SET_TOKEN: (state, token) => {state.token = token},SET_ID: (state, id) => {state.id = id},SET_NAME: (state, name) => {state.name = name},SET_AVATAR: (state, avatar) => {state.avatar = avatar},SET_ROLES: (state, roles) => {state.roles = roles},SET_PERMISSIONS: (state, permissions) => {state.permissions = permissions}},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.publicKeyconst username = userInfo.username.trim()//调用加密方法(传密码和公钥)const password = encrypt(userInfo.password, publicKey)const code = userInfo.codeconst uuid = userInfo.uuidlogin(username, password, code, uuid).then(res => {setToken(res.token)commit('SET_TOKEN', res.token)resolve()}).catch(error => {reject(error)})})})},// 获取用户信息GetInfo({ commit, state }) {return new Promise((resolve, reject) => {getInfo().then(res => {const user = res.userconst avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组commit('SET_ROLES', res.roles)commit('SET_PERMISSIONS', res.permissions)} else {commit('SET_ROLES', ['ROLE_DEFAULT'])}commit('SET_ID', user.userId)commit('SET_NAME', user.userName)commit('SET_AVATAR', avatar)resolve(res)}).catch(error => {reject(error)})})},// 退出系统LogOut({ commit, state }) {return new Promise((resolve, reject) => {logout(state.token).then(() => {commit('SET_TOKEN', '')commit('SET_ROLES', [])commit('SET_PERMISSIONS', [])removeToken()resolve()}).catch(error => {reject(error)})})},// 前端 登出FedLogOut({ commit }) {return new Promise(resolve => {commit('SET_TOKEN', '')removeToken()resolve()})}}
}export default user

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.publicKeyconsole.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" });}}

这样就完成改造了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/520142.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 获取项目内的资源/配置文件

【getResourceAsStream】是java中用于获取项目内资源的常用方法,能够返回一个数据流,从而允许我们读取指定路径下的资源文件。这个方法可以用来读取各种类型的资源文件,包括但不限于文本文件、图像文件、配置文件等。 要使用getResourceAsStr…

Ansible 基础入门

2)Ansible 介绍 Ansible 基本概念 Ansible 是一种自动化运维工具,基于 Paramiko 开发的,并且基于模块化工作,Ansible 是一种集成 IT 系统的配置管理、应用部署、执行特定任务的开源平台,它是基于 Python 语言&#xf…

19-Java中介者模式 ( Mediator Pattern )

Java中介者模式 摘要实现范例 中介者模式(Mediator Pattern)提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护中介者模式是用来降低多个对象和类之间的通信复杂性中介者模式属于行为型模式…

内衣洗衣机怎么选?2024年度最新爆品内衣洗衣机测评

内衣裤洗衣机是一种非常实用的洗衣机,可以有效地保护内衣和贴身衣物的质量和卫生,相比于普通的家用大型洗衣机,内衣裤洗衣机在容量、洗涤方式、控制方式和价格等方面有很大的不同之处,如果您经常需要清洗内衣和贴身衣物&#xff0…

Python实战小项目-骰子模拟器+Turtle绘图

Python实战小项目-骰子模拟器Turtle绘图 骰子模拟器Turtle绘图 骰子模拟器 导入了random模块,该模块提供了生成随机数的功能。 定义了两个变量min_val和max_val,分别表示骰子的最小值和最大值。在这个例子中,骰子的最小值为1,最大…

SpringMVC 中的常用注解和用法

⭐ 作者:小胡_不糊涂 🌱 作者主页:小胡_不糊涂的个人主页 📀 收录专栏:JavaEE 💖 持续更文,关注博主少走弯路,谢谢大家支持 💖 注解 1. MVC定义2. 注解2.1 RequestMappin…

【python基础学习11课_异常机制】

一、异常 1、异常的定义 异常:程序无法继续执行异常会中断程序执行异常处理,是为了不中断程序执行。而不是避免错误。有些代码是报错就是要暴露出来有了异常机制,错误的代码报错后抛出异常,代码从上到下,报错代码后面…

AI嵌入式CanMV-K230项目(1)-简介

文章目录 前言一、嘉楠的产品体系二、开发板介绍三、应用领域总结 前言 前一些列文章我们介绍了K210的使用方法,近期嘉楠科技发布了最新一版的K230芯片,下面我们来了解下这款芯片,后续我们将介绍该款芯片开发板的使用方法。 一、嘉楠的产品体…

javascript操作BOM的方法

目录 1.window.alert() 2.window.confirm() 3.window.prompt() 4.window.location() 5.window.navigator() 6.window.screen() 7.window.history() 8.window.setTimeout() 和 window.clearTimeout() 9.window.setInterval() 和 window.clearInterval() BOM&#xff08…

基于51单片机的万年历-心率脉搏计仿真及源程序-保存心率记录

基于51单片机的万年历-心率脉搏计仿真及源程序-保存心率记录 一、系统方案 1、本设计采用51单片机作为主控器。 2、液晶1602显示。 3、DS1302万年历,测心率,按键设置万年历、心率上下限,不在范围蜂鸣器报警。 4、心率测量值保存3组数据。 二、…

C语言内存优化实用指南

一、引言 在C语言编程中,内存管理是一项至关重要的任务。有效的内存优化可以提升程序的性能,减少资源消耗,并防止可能出现的内存泄漏和溢出问题。以下是一些关于C语言内存优化的实用指南。 二、理解内存管理 在C语言中,程序员需…

蓝桥杯物联网竞赛_STM32L071_11_知识体系的查漏与补缺

太久没学单片机了,再重新过一遍查漏补缺,对其中之前没怎么在意的,而现在又发觉的问题进行再分析与补充 1. debug serial wire是干什么用的 这个东西我勾选不勾选都对我的程序没有什么影响,我很好奇是干什么用的,网上查…