当前位置: 首页 > news >正文

在SpringBoot+VUE中 实现登录-RSA的加密解密

步骤-先理清楚在动手

  1. 前端首先调用后端的公钥接口,
  2. 在前端加密密码传输至后端登录接口
  3. 后端用私钥解密码
  4. 拿着用户名去数据库查询出来的盐值加密的 密码1
  5. 用私钥解密密码登录密码加盐值得到 密码2
  6. 比较密码1与密码2,相同则登录成功,跳转首页|其他页面
前端实现
  1. 如果当前vue项目没有安装 jsencrypt 你需要先使用 npm 来安装 jsencrypt。

使用 npm:

npm install jsencrypt --save

  1. 调用后端接口获取公钥。
 created() {this.getPublicKey();},methods: {async getPublicKey() {try {// 此处为调用后端接口。const response = await getPublicKey();if (response.data.code === 200) {this.publicKey = response.data.data;}}catch (error) {Message.error(error.message);}}}
  1. 根据获取到的公钥和 jsencrypt 加密用户输入的密码
import JSEncrypt from 'jsencrypt';// 提交表单-此处只处理了密码信息,后续的接口和 token以及页面跳转均未处理
async handleSubmit() {// 验证if (!this.password) {Message.error('请输入密码!');return;}// 加密const crypt = new JSEncrypt();crypt.setPublicKey(this.publicKey);// 得到加密后的密码const encrypted = crypt.encrypt(this.password);// 无感跳转页面 // this.$router.push({path: '/Index'});}

此时就可以向后端发送登录请求了。

后端实现
  1. 工具类
import java.util.Base64;public class Base64Util {public static byte[] encode(byte[] signData) {return Base64.getEncoder().encode(signData);}public static byte[] decode(String signData) {return Base64.getDecoder().decode(signData);}public static String encodeToStr(byte[] signData) {return new String(Base64.getEncoder().encode(signData));}public static String decodeToStr(String signData) {return new String(Base64.getDecoder().decode(signData));}
}

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;/*** Java加密解密工具.3DES SHA1 MD5 BASE64编码 AES加密** @author 党泽坤*/
public class EncryptUtil {// 密钥private final static String secretKey = "dzkandzhj202410$#365#001";// 向量private final static String iv = "01234567";// 加解密统一使用的编码方式private final static String encoding = "utf-8";// 无需创建对象private EncryptUtil() {}/*** SHA1加密Bit数据** @param source byte数组* @return 加密后的byte数组*/public static byte[] SHA1Bit(byte[] source) {try {MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1");sha1Digest.update(source);byte targetDigest[] = sha1Digest.digest();return targetDigest;} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}/*** SHA1加密字符串数据** @param source 要加密的字符串* @return 加密后的字符串*/public static String SHA1(String source) {return byte2HexStr(SHA1Bit(source.getBytes()));}/*** MD5加密Bit数据** @param source byte数组* @return 加密后的byte数组*/public static byte[] MD5Bit(byte[] source) {try {// 获得MD5摘要算法的 MessageDigest对象MessageDigest md5Digest = MessageDigest.getInstance("MD5");// 使用指定的字节更新摘要md5Digest.update(source);// 获得密文return md5Digest.digest();} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}/*** MD5加密字符串,32位长** @param source 要加密的内容* @return 加密后的内容*/public static String MD5(String source) {return byte2HexStr(MD5Bit(source.getBytes()));}/*** BASE64编码** @param source 要编码的字符串* @return 编码过的字符串* @throws UnsupportedEncodingException*/public static String encodeBASE64(String source) throws UnsupportedEncodingException {return Base64.getEncoder().encodeToString(source.getBytes(encoding));}/*** BASE64解码** @param encodeSource 编码过的字符串* @return 编码前的字符串* @throws UnsupportedEncodingException*/public static String decodeBASE64(String encodeSource) throws UnsupportedEncodingException {return new String(Base64.getDecoder().decode(encodeSource), encoding);}/*** AES加密** @param content  待加密的内容* @param password 加密密码* @return*/public static byte[] encryptBitAES(byte[] content, String password) {try {Cipher encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// 创建密码器encryptCipher.init(Cipher.ENCRYPT_MODE, getKey(password));// 初始化byte[] result = encryptCipher.doFinal(content);return result; // 加密} catch (Exception e) {throw new RuntimeException(e);}// return null;}/*** AES解密** @param content  待解密内容* @param password 解密密钥* @return*/public static byte[] decryptBitAES(byte[] content, String password) {try {Cipher decryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// 创建密码器decryptCipher.init(Cipher.DECRYPT_MODE, getKey(password));// 初始化return decryptCipher.doFinal(content); // 加密结果} catch (Exception e) {throw new RuntimeException(e);}// return null;}/*** AES字符串加密** @param content  待加密的内容* @param password 加密密码* @return*/public static String encryptAES(String content, String password) {return byte2HexStr(encryptBitAES(content.getBytes(), password));}/*** AES字符串解密** @param content  待解密内容* @param password 解密密钥* @return*/public static String decryptAES(String content, String password) {return new String(decryptBitAES(hexStr2Bytes(content), password));}/*** 从指定字符串生成密钥** @param password 构成该秘钥的字符串* @return 生成的密钥* @throws NoSuchAlgorithmException*/private static Key getKey(String password) throws NoSuchAlgorithmException {SecureRandom secureRandom = new SecureRandom(password.getBytes());// 生成KEYKeyGenerator kgen = KeyGenerator.getInstance("AES");kgen.init(128, secureRandom);SecretKey secretKey = kgen.generateKey();byte[] enCodeFormat = secretKey.getEncoded();// 转换KEYSecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");return key;}/*** 将byte数组转换为表示16进制值的字符串. 如:byte[]{8,18}转换为:0812 和 byte[]* hexStr2Bytes(String strIn) 互为可逆的转换过程.** @param bytes 需要转换的byte数组* @return 转换后的字符串*/public static String byte2HexStr(byte[] bytes) {int bytesLen = bytes.length;// 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍StringBuffer hexString = new StringBuffer(bytesLen * 2);for (int i = 0; i < bytesLen; i++) {// 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制String hex = Integer.toHexString(bytes[i] & 0xFF);if (hex.length() < 2) {hexString.append(0);// 如果为1位 前面补个0}hexString.append(hex);}return hexString.toString();}/*** 将表示16进制值的字符串转换为byte数组, 和 String byte2HexStr(byte[] bytes) 互为可逆的转换过程.** @param strIn* @return 转换后的byte数组*/public static byte[] hexStr2Bytes(String strIn) {byte[] arrB = strIn.getBytes();int iLen = arrB.length;// 两个字符表示一个字节,所以字节数组长度是字符串长度除以2byte[] arrOut = new byte[iLen / 2];for (int i = 0; i < iLen; i = i + 2) {String strTmp = new String(arrB, i, 2);arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);}return arrOut;}/*** 3DES加密** @param plainText 普通文本* @return* @throws Exception*/public static String d3esEncode(String plainText) {Key deskey = null;byte[] encryptData = null;try {DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");deskey = keyfactory.generateSecret(spec);Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");IvParameterSpec ips = new IvParameterSpec(iv.getBytes());cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);encryptData = cipher.doFinal(plainText.getBytes(encoding));} catch (Exception e) {e.printStackTrace();}return Base64.getEncoder().encodeToString(encryptData);}/*** 3DES解密** @param encryptText 加密文本* @return* @throws Exception*/public static String d3esDecode(String encryptText) {Key deskey = null;byte[] decryptData = null;String result = "";if (null != encryptText && !"".equals(encryptText)) {try {DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");deskey = keyfactory.generateSecret(spec);Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");IvParameterSpec ips = new IvParameterSpec(iv.getBytes());cipher.init(Cipher.DECRYPT_MODE, deskey, ips);decryptData = cipher.doFinal(Base64.getDecoder().decode(encryptText));result = new String(decryptData, encoding);} catch (Exception e) {e.printStackTrace();}}return result;}public static void main(String[] args) {// 此处测试}
}

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;/*** <p>* RSA公钥/私钥/签名工具包* </p>* <p>* 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)* </p>* <p>* 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>* 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>* 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全* </p>** @author IceWee* @version 1.0* @date 2012-4-26*/
public class RSAUtils {/*** 加密算法RSA*/public static final String KEY_ALGORITHM = "RSA";/*** 签名算法*/public static final String SIGNATURE_ALGORITHM = "MD5withRSA";/*** 获取公钥的key*/private static final String PUBLIC_KEY = "RSAPublicKey";/*** 获取私钥的key*/private static final String PRIVATE_KEY = "RSAPrivateKey";/*** RSA最大加密明文大小*/private static final int MAX_ENCRYPT_BLOCK = 64;/*** RSA最大解密密文大小*/private static final int MAX_DECRYPT_BLOCK = 128;/*** 加密算法RSA/ECB/PKCS1Padding和填充模式*/private static final String ALGORITHM = "PBKDF2WithHmacSHA256";/*** 迭代次数*/private static final int ITERATIONS = 65536;/*** 密钥长度*/private static final int KEY_LENGTH = 256;/*** 盐长度 (字节长度)*/private static final int SALT_LENGTH = 16;/*** <p>* 生成密钥对(公钥和私钥)* </p>** @return* @throws Exception*/public static Map<String, Object> genKeyPair() {KeyPairGenerator keyPairGen = null;try {keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGen.initialize(1024);KeyPair keyPair = keyPairGen.generateKeyPair();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}/*** <p>* 获取私钥* </p>** @param keyMap 密钥对* @return* @throws Exception*/public static String getPrivateKey(Map<String, Object> keyMap) {Key key = (Key) keyMap.get(PRIVATE_KEY);return Base64Util.encodeToStr(key.getEncoded());}/*** <p>* 获取公钥* </p>** @param keyMap 密钥对* @return* @throws Exception*/public static String getPublicKey(Map<String, Object> keyMap) {Key key = (Key) keyMap.get(PUBLIC_KEY);return Base64Util.encodeToStr(key.getEncoded());}/*** <p>* 用私钥对信息生成数字签名* </p>** @param data       已加密数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static String sign(byte[] data, String privateKey) throws Exception {byte[] keyBytes = Base64Util.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initSign(privateK);signature.update(data);return Base64Util.encodeToStr(signature.sign());}/*** <p>* 校验数字签名* </p>** @param data      已加密数据* @param publicKey 公钥(BASE64编码)* @param sign      数字签名* @return* @throws Exception*/public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {byte[] keyBytes = Base64Util.decode(publicKey);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PublicKey publicK = keyFactory.generatePublic(keySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initVerify(publicK);signature.update(data);return signature.verify(Base64Util.decode(sign));}/*** <P>* 私钥解密* </p>** @param encryptedData 已加密数据* @param privateKey    私钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {byte[] keyBytes = Base64Util.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, privateK);int inputLen = encryptedData.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/*** <p>* 公钥解密* </p>** @param encryptedData 已加密数据* @param publicKey     公钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {byte[] keyBytes = Base64Util.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, publicK);int inputLen = encryptedData.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/*** <p>* 公钥加密* </p>** @param data      源数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {byte[] keyBytes = Base64Util.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, publicK);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/*** <p>* 私钥加密* </p>** @param data       源数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {byte[] keyBytes = Base64Util.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, privateK);int inputLen = data.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/*** java端公钥加密*/public static String encryptedDataOnJava(String data, String publicKey) {try {data = Base64Util.encodeToStr(encryptByPublicKey(data.getBytes(), publicKey));} catch (Exception e) {e.printStackTrace();}return data;}/*** java端私钥解密*/public static String decryptDataOnJava(String data, String privateKey) {String temp = "";try {byte[] rs = Base64Util.decode(data);// 解密 以utf-8的方式生成字符串temp = new String(RSAUtils.decryptByPrivateKey(rs, privateKey), StandardCharsets.UTF_8);} catch (Exception e) {e.printStackTrace();}return temp;}public static void main(String[] args) {try {Map<String, Object> keyMap = RSAUtils.genKeyPair();String publicKey = RSAUtils.getPublicKey(keyMap);String privateKey = RSAUtils.getPrivateKey(keyMap);System.out.println("publicKey = " + publicKey);System.out.println("privateKey = " + privateKey);System.out.println("=============================");String s = encryptedDataOnJava("123456", publicKey);System.out.println("java端公钥加密  " + s);String s21 = decryptDataOnJava(s, privateKey);System.out.println("java端私钥解密 = " + s21);//byte[] bytes = generateSalt();//System.out.println("生成的盐 = " + bytes);String s1 = "9be08179ba82f8e2068928c2494b577c";System.out.println("16制字符 = " + s1.length());byte[] bytes1 = hexToBytes(s1);//System.out.println("bytesToHex(bytes) = " + Arrays.equals(bytes, bytes1));String ss = hashPassword("123456", bytes1);System.out.println("生成的哈希值 = " + ss.equals("zDuIyDjB1Qwi54j2j2fyPsmkvAjUNw/rT/92pAG6fNg="));} catch (Exception e) {e.printStackTrace();}}/*** =============================== 密码加盐 =======================*//*** 生成随机盐** @return* @throws NoSuchAlgorithmException*/public static byte[] generateSalt() {try {   // 使用 SecureRandom 来生成高质量的随机数SecureRandom sr  = SecureRandom.getInstanceStrong();byte[] salt = new byte[SALT_LENGTH];sr.nextBytes(salt);return salt;} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}/*** 将字节数组转换为十六进制字符串** @param bytes* @return*/public static String bytesToHex(byte[] bytes) {StringBuilder sb = new StringBuilder();for (byte b : bytes) {sb.append(String.format("%02x", b));}return sb.toString();}/*** 将十六进制字符串转换为字节数组** @param hex* @return byte[]*/public static byte[] hexToBytes(String hex) {int len = hex.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)+ Character.digit(hex.charAt(i + 1), 16));}return data;}/*** ================================ 密码加密 ================================*//*** 根据盐和密码生成加密密码(哈希值)** @param password 密码* @param salt     盐* @return 哈希值(Base64编码)* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException*/public static String hashPassword(String password, byte[] salt) {try {// 创建PBEKeySpec对象PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH);// 创建SecretKeyFactory对象SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);// 生成密钥byte[] hash = factory.generateSecret(spec).getEncoded();// 使用Base64编码return Base64.getEncoder().encodeToString(hash);} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {throw new RuntimeException(e);}}/*** 校验密码是否匹配* @param dbHashPassword     数据库中存储的密码* @param inputPassword     用户输入的密码* @param dbSalt     数据库中存储的盐* @return  true 匹配成功 false 匹配失败*/public static boolean hashPasswordIsMatch(String dbHashPassword, String inputPassword, String dbSalt) {byte[] byteSalts = hexToBytes(dbSalt);String newHashedPassword = hashPassword(inputPassword, byteSalts);return dbHashPassword.equals(newHashedPassword);}}
  1. Controller 实现。
	/*** 获取公钥** @param request   HttpServletRequest对象* @return*/@ApiOperation(value = "登陆,获取公钥", httpMethod = "GET")@GetMapping("/publicKey")public String publicKey(HttpServletRequest request) {return generateKey(request);}/*** 生成随机码* @param request HttpServletRequest对象*/private String generateKey(HttpServletRequest request) {Map<String, Object> keyMap = RSAUtils.genKeyPair();String publicKey = RSAUtils.getPublicKey(keyMap);String privateKey = RSAUtils.getPrivateKey(keyMap);request.getSession().setAttribute("privateKey", privateKey);return StringUtils.isBlank(publicKey) ? "" : publicKey;}/*** 登录* 此处简化,根据自己业务自定* @param request     HttpServletRequest对象* @param loginRequest       登录请求体*/@ApiOperation(value = "登录", httpMethod = "POST")@PostMapping(value = "/login")public void secondLoginCostDashboard(HttpServletRequest request, @RequestBody LoginRequest loginRequest) {String privateKey = (String) request.getSession().getAttribute("privateKey");Validator.validateFalse(StringUtils.isBlank(privateKey), "鉴权失败,请刷新页面,重试!");String account = loginRequest.getUserAccount();// 获取登录人信息SysUser sysUser = userExist(account);String inputPassword = loginRequest.getPassword();// 密码解密String decryptPassword = RSAUtils.decryptDataOnJava(inputPassword, privateKey);// 输入和db存入的密码对比, 盐boolean isMatch = RSAUtils.hashPasswordIsMatch(sysUser.getPassword(), decryptPassword, sysUser.getSalt());Validator.validateTrue(isMatch,"密码输入错误,请检查!")  ;}/*** 重设密码* @param request     HttpServletRequest对象* @param loginRequest       登录请求体*/@ApiOperation(value = "重设密码", httpMethod = "POST")@PostMapping(value = "/restPassword")public void updatePasswordCostDashboard(HttpServletRequest request, @RequestBody LoginRequest loginRequest) {String privateKey = (String) request.getSession().getAttribute("privateKey");Validator.validateFalse(StringUtils.isBlank(privateKey), "鉴权失败,请刷新页面,重试!");String account = loginRequest.getUserAccount();SysUser sysUser = userExist(account);// 原密码String oldPwd = loginRequest.getPassword();String oldDecryptPwd = RSAUtils.decryptDataOnJava(oldPwd, privateKey);boolean isMatch = RSAUtils.hashPasswordIsMatch(sysUser.getPassword(), oldDecryptPwd, sysUser.getSalt());Validator.validateTrue(isMatch,"原密码输入错误,请检查!")  ;// 新密码String newPwd = loginRequest.getNewPassword();// 解密后的新密码String newDecryptPwd = RSAUtils.decryptDataOnJava(newPwd, privateKey);// 生成盐byte[] saltBytes = RSAUtils.generateSalt();String saltStr = RSAUtils.bytesToHex(saltBytes);// 加盐后的密码String newHashPassword =  RSAUtils.hashPassword(newDecryptPwd, saltBytes);sysUser.setPassword(newHashPassword);sysUser.setSalt(saltStr);// 调用更新接口}

请求实体Vo

public class LoginRequest {/*** 登录账号*/private String userAccount ;/*** 密码*/private String password;/*** 公钥*/private String publicKey;/*** 新密码*/private String newPassword;
}

相关文章:

在SpringBoot+VUE中 实现登录-RSA的加密解密

步骤-先理清楚在动手 前端首先调用后端的公钥接口,在前端加密密码传输至后端登录接口后端用私钥解密码拿着用户名去数据库查询出来的盐值加密的 密码1用私钥解密密码登录密码加盐值得到 密码2比较密码1与密码2,相同则登录成功&#xff0c;跳转首页&#xff5c;其他页面 前端实…...

基于Android11简单分析audio_policy_configuration.xml

开篇先贴上一个高通的例子&#xff0c;后续基于此文件做具体分析。 1 <?xml version"1.0" encoding"UTF-8" standalone"yes"?> 2 <!-- Copyright (c) 2016-2019, The Linux Foundation. All rights reserved 3 Not a Contribut…...

kafka-manager修改zookeeper端口号后启动仍然连接2181端口

问题描述&#xff1a; zookeeper默认端口号修改为了2182&#xff0c;kafka-manager的配置文件application.conf中也已经修改了zkhosts为新的端口号&#xff0c;然而启动kafka-manger时报错连接连接超时&#xff0c;发现连接的还是2181端口&#xff0c;很奇怪&#xff1f;&…...

RabbitMQ 入门(三)SpringAMQP

一、Spring AMQP 简介 SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址&#xff1a;https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能&#xff1a; - 自动…...

celery 项目中mysql 数据库连接数耗尽事故记录

python 项目中使用 celery 中导致mysql数据库连接耗尽记录【mysql数据库连接池使用错误】 结论&#xff1a;由于使用 celery 进行项目的多任务管理&#xff0c;在worker任务定义的过程中&#xff0c;使用了 dbutils 中的 PooledDB 连接池进行 mysql数据库连接&#xff0c; 因此…...

Python数据分析-Scipy科学计算法

1.认识Scipy SciPy&#xff08;发音为 "Sigh Pie"&#xff09;是一个开源的 Python 算法库和数学工具包。 通常与 NumPy、Matplotlib 和 pandas 等库一起使用&#xff0c;这些库共同构成了 Python 的科学计算基础。 2.使用Scipy基本函数 2.1 引用Scipy函数 impor…...

【Python Django + Vue】酒店在线预订系统:用技术说话!

&#x1f393; 作者&#xff1a;计算机毕设小月哥 | 软件开发专家 &#x1f5a5;️ 简介&#xff1a;8年计算机软件程序开发经验。精通Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等技术栈。 &#x1f6e0;️ 专业服务 &#x1f6e0;️ 需求定制化开发源码提…...

禁用微软的windos安全中心

目录 一、为什么禁用 二、WDControl_1.5.0程序禁用windows安全中心 步骤1--- 步骤2--- 三、禁用widows安全中心成功 一、为什么禁用 描述&#xff1a;下载第三方软件常常会收到病毒防护秒杀&#xff0c; 第1---直接无法下载 第2---提前下载在U盘解压会被干掉程序文件 …...

2.html编辑器介绍

html编辑器介绍 HTML 编辑器推荐 理论上我们可以使用记事本进行html编码和开发&#xff0c;但是在实际开发html页面的时候&#xff0c;使用一些专业的开发工具可以使我们更加快速和高效的进行开发&#xff0c;下面介绍几种开发工具&#xff1a; VS Code&#xff1a;https://…...

树莓派应用--AI项目实战篇来啦-17.YOLOv8目标检测-安全帽检测

1. YOLOv8介绍 YOLOv8是Ultralytics公司2023年推出的Yolo系列目标检测算法&#xff0c;可以用于图像分类、物体检测和实例分割等任务。YOLOv8作为YOLO系列算法的最新成员&#xff0c;在损失函数、Anchor机制、样本分配策略等方面进行了全面优化和创新。这些改进不仅提高了模型的…...

git-secret介绍

git-secret介绍 git-secret 是一个与git兼容的命令行工具,旨在安全地存储和管理敏感数据,如源代码中的密码、密钥以及敏感文件。它通过 GPG 加密来保护文件,确保只有授权的用户才能访问这些敏感信息。 使用流程 1、安装 Git-Secret:在本地开发环境中安装 git-secret。 2…...

【实战】Nginx+Lua脚本+Redis 实现自动封禁访问频率过高IP

大家好&#xff0c;我是冰河~~ 自己搭建的网站刚上线&#xff0c;短信接口就被一直攻击&#xff0c;并且攻击者不停变换IP&#xff0c;导致阿里云短信平台上的短信被恶意刷取了几千条&#xff0c;加上最近工作比较忙&#xff0c;就直接在OpenResty上对短信接口做了一些限制&am…...

计算机专业大一课程:线性代数探秘

计算机专业大一课程&#xff1a;线性代数探秘 对于计算机专业的大一新生来说&#xff0c;线性代数是一门基础且重要的课程。它不仅是数学的一个分支&#xff0c;更是计算机科学中不可或缺的工具。那么&#xff0c;线性代数究竟包含哪些内容&#xff0c;对我们的计算机学习有何…...

vscode写markdown插入图片视频并放在指定目录

目录 前言正文 前言 各种云文档非常好用&#xff0c;但是当你想把这些资料保存在本地时&#xff0c;markdown我觉得是最好的选择 markdown编辑器也有很多&#xff0c;但我还是觉得vscode最好用&#xff0c;直接粘贴文件就可以插入也类似云文档的使用体验&#xff0c;但是想要…...

鸿蒙富文本显示

1.使用 RichText 组件&#xff08;ArkTS&#xff09; 背景知识&#xff1a;在 ArkTS&#xff08;一种鸿蒙应用开发语言&#xff09;中&#xff0c;RichText组件提供了更强大的富文本显示功能。它允许设置不同的文本样式&#xff0c;包括字体、颜色、字号等多种属性。 Rich Te…...

手写mybatis之细化XML语句构建器,完善静态SQL解析

前言 1&#xff1a;在流程上&#xff0c;通过 DefaultSqlSession#selectOne 方法调用执行器&#xff0c;并通过预处理语句处理器 PreparedStatementHandler 执行参数设置和结果查询。 2&#xff1a;那么这个流程中我们所处理的参数信息&#xff0c;也就是每个 SQL 执行时&#…...

使用Milvus和Llama-agents构建更强大的Agent系统

代理&#xff08;Agent&#xff09;系统能够帮助开发人员创建智能的自主系统&#xff0c;因此变得越来越流行。大语言模型&#xff08;LLM&#xff09;能够遵循各种指令&#xff0c;是管理 Agent 的理想选择&#xff0c;在许多场景中帮助我们尽可能减少人工干预、处理更多复杂任…...

Python 工具库每日推荐【Arrow】

文章目录 引言Python时间日期处理库的重要性今日推荐:Arrow工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:跨时区会议安排器案例分析高级特性时间范围和区间自定义时间格式扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeScript…...

Win10 安装 Redis 数据库

一、Redis 数据库介绍 Redis 是一个开源的高性能键值对&#xff08;key-value&#xff09;的非关系型数据库。它通常用作数据结构服务器&#xff0c;支持多种类型的数据结构&#xff0c;如字符串&#xff08;strings&#xff09;、哈希&#xff08;hashes&#xff09;、列表&a…...

使用springboot生成war包

1.生成war包 1.1 更改pom包 打开一个springboot 项目 &#xff0c;右击项目名从项目管理器打开 在pom.xml文件中插入以下两个依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

Xcode 16 集成 cocoapods 报错

基于 Xcode 16 新建工程项目&#xff0c;集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...