自学内容网 自学内容网

在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());
        // 生成KEY
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        // 转换KEY
        SecretKeySpec 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;

        // 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
        byte[] 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;
}

原文地址:https://blog.csdn.net/weixin_44835297/article/details/142881402

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!