赞
踩
http://doc.ruoyi.vip/ruoyi-vue/
若依前后端环境分离版本,本地部署好前后端环境后,访问登录接口密码是明文的,这样显然是不安全的,如下图所示:
①、后端生成随机公钥和私钥;
②、前端拿到公钥,集成jsencrypt实现密码加密;
③、前端传输加密后的秘密给后端;
④、后端通过私钥对加密后的秘钥进行解密,验证密码
https://doc.ruoyi.vip/ruoyi-vue/document/cjjc.html#%E9%9B%86%E6%88%90jsencrypt%E5%AE%9E%E7%8E%B0%E5%AF%86%E7%A0%81%E5%8A%A0%E5%AF%86%E4%BC%A0%E8%BE%93%E6%96%B9%E5%BC%8F
- package com.ruoyi.business.utils;
-
- import org.apache.commons.codec.binary.Base64;
- 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 RSAUtil {
- // Rsa 私钥 也可固定秘钥对 若依原写法(不安全)
- public static String privateKeys = "";
- private static String publicKeyStr = "";
- private static String privateKeyStr = "";
- private static final RSAKeyPair rsaKeyPair = new RSAKeyPair();
-
- /**
- * 私钥解密
- *
- * @param text 待解密的文本
- * @return 解密后的文本
- */
- public static String decryptByPrivateKey(String text) throws Exception {
- 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;
- }
- }
- }
说明:
RSAUtil中添加了@Component注解,generateKeyPair()构建秘钥对添加了@Bean注解,在项目启动时通过@Bean的方式将普通类实例化到Spring容器中,所以当系统启动后,每次调用接口得到的公钥&私钥是一样的,服务重启后,公钥&私钥重新生成。
- /**
- * 获取公钥:前端用来密码加密
- * @return
- */
- @GetMapping("/getPublicKey")
- public RSAUtil.RSAKeyPair getPublicKey() {
- return RSAUtil.rsaKeyPair();
- }
.antMatchers("/getPublicKey").permitAll()
- /**
- * 登录验证
- *
- * @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
- {
- UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,RSAUtil.decryptByPrivateKey(password));
- AuthenticationContextHolder.setContext(authenticationToken);
- // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
- authentication = 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());
- // 生成token
- return 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 = RSAUtil.decryptByPrivateKey(oldPassword);
- newPassword = RSAUtil.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("修改密码异常,请联系管理员");
- }
==========================O(∩_∩)O 后端修改over O(∩_∩)O==========================
- import request from '@/utils/request'
-
- // 获取公钥
- export function getPublicKey() {
- return request({
- url: '/getPublicKey',
- method: 'get',
- })
- }
-
- // 登录方法
- export function login(username, password, code, uuid) {
- const data = {
- username,
- password,
- code,
- uuid
- }
- return request({
- url: '/login',
- headers: {
- isToken: false
- },
- method: 'post',
- data: data
- })
- }
-
- // 注册方法
- export function register(data) {
- return request({
- url: '/register',
- headers: {
- isToken: false
- },
- method: 'post',
- data: data
- })
- }
-
- // 获取用户详细信息
- export function getInfo() {
- return request({
- url: '/getInfo',
- method: 'get'
- })
- }
-
- // 退出方法
- export function logout() {
- return request({
- url: '/logout',
- method: 'post'
- })
- }
-
- // 获取验证码
- export function getCodeImg() {
- return request({
- url: '/captchaImage',
- headers: {
- isToken: false
- },
- method: 'get',
- timeout: 20000
- })
- }
- import { getToken, setToken, removeToken } from '@/utils/auth'
- import { login, logout, getInfo, getPublicKey } from '@/api/login'
- import {encrypt} from "../../utils/jsencrypt";
-
- const user = {
- state: {
- token: getToken(),
- name: '',
- avatar: '',
- roles: [],
- permissions: []
- },
-
- mutations: {
- SET_TOKEN: (state, token) => {
- state.token = token
- },
- 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.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)
- })
- })
- })
- },
-
- // 获取用户信息
- GetInfo({ commit, state }) {
- return new Promise((resolve, reject) => {
- getInfo().then(res => {
- const user = res.user
- const 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_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
注意事项:注意上方的导包
- <template>
- <el-form ref="form" :model="user" :rules="rules" label-width="80px">
- <el-form-item label="旧密码" prop="oldPassword">
- <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password/>
- </el-form-item>
- <el-form-item label="新密码" prop="newPassword">
- <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password/>
- </el-form-item>
- <el-form-item label="确认密码" prop="confirmPassword">
- <el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" size="mini" @click="submit">保存</el-button>
- <el-button type="danger" size="mini" @click="close">关闭</el-button>
- </el-form-item>
- </el-form>
- </template>
-
- <script>
- import { updateUserPwd } from "@/api/system/user";
- import { getPublicKey } from '@/api/login';
- import { encrypt } from '@/utils/jsencrypt';
-
- export default {
- data() {
- const equalToPassword = (rule, value, callback) => {
- if (this.user.newPassword !== value) {
- callback(new Error("两次输入的密码不一致"));
- } else {
- callback();
- }
- };
- return {
- user: {
- oldPassword: undefined,
- newPassword: undefined,
- confirmPassword: undefined
- },
- // 表单校验
- rules: {
- oldPassword: [
- { required: true, message: "旧密码不能为空", trigger: "blur" }
- ],
- newPassword: [
- { required: true, message: "新密码不能为空", trigger: "blur" },
- { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }
- ],
- confirmPassword: [
- { required: true, message: "确认密码不能为空", trigger: "blur" },
- { required: true, validator: equalToPassword, trigger: "blur" }
- ]
- }
- };
- },
- 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.$tab.closePage();
- }
- }
- };
- </script>
- 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) // 对数据进行解密
- }
https://blog.csdn.net/weixin_56567361/article/details/124961493
- 链接:https://pan.baidu.com/s/1YKnAcixZGn5zeUkSti1DCA?pwd=yyds
- 提取码:yyds
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。