前后端加密传数据实现方案

发布于:2025-08-12 ⋅ 阅读:(22) ⋅ 点赞:(0)

前端加解密工具类(AES.js):

import CryptoJS from 'crypto-js';
//加密
export const aesEncrypt = (word, keyStr) => {
    keyStr = keyStr ? keyStr : 'abcdsxyzhkj12345'; //判断是否存在ksy,不存在就用定义好的key
    const key = CryptoJS.enc.Utf8.parse(keyStr);
    const srcs = CryptoJS.enc.Utf8.parse(word);
    const encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.toString();
}

/**
 * AES解密方法,兼容Java后端BASE64Encoder编码的加密字符串
 * @param {string} word - 需要解密的内容
 * @param {string} keyStr - 解密密钥,默认为'abcdsxyzhkj12345'
 * @returns {string} - 返回解密后的字符串
 */
export const aesDecrypt = (word, keyStr) => {
  if (!word) {
    return '';
  }

  keyStr = keyStr ? keyStr : 'abcdsxyzhkj12345';
  const key = CryptoJS.enc.Utf8.parse(keyStr);

  try {
    // 处理Java BASE64Encoder编码的字符串
    // 1. 确保BASE64字符串格式正确(替换可能的换行符和填充字符)
    let formattedWord = word.replace(/[\r\n]/g, '');

    // 2. 检查是否需要转换为CryptoJS可接受的BASE64格式
    // Java的BASE64Encoder可能会添加换行符和使用不同的填充字符
    if (formattedWord.indexOf('+') === -1 && formattedWord.indexOf('/') === -1) {
      // 如果不包含标准BASE64字符,可能需要转换
      formattedWord = formattedWord.replace(/-/g, '+').replace(/_/g, '/');
    }

    // 3. 确保BASE64字符串长度是4的倍数(添加必要的填充)
    while (formattedWord.length % 4 !== 0) {
      formattedWord += '=';
    }

    // 4. 尝试直接解密
    try {
      const decrypt = CryptoJS.AES.decrypt(formattedWord, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
      });

      const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);

      if (decryptedStr && decryptedStr.length > 0) {
        return decryptedStr;
      }
    } catch (e) {
      console.log("直接解密失败,尝试其他方法", e);
    }

    // 5. 如果直接解密失败,尝试先解析BASE64
    try {
      const parsedWord = CryptoJS.enc.Base64.parse(formattedWord);
      const ciphertext = CryptoJS.lib.CipherParams.create({
        ciphertext: parsedWord
      });

      const decrypt = CryptoJS.AES.decrypt(ciphertext, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
      });

      const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);

      if (decryptedStr && decryptedStr.length > 0) {
        return decryptedStr;
      }
    } catch (e) {
      console.log("BASE64解析后解密失败", e);
    }

    // 6. 尝试使用CryptoJS的格式
    try {
      const cipherParams = {
        ciphertext: CryptoJS.enc.Base64.parse(formattedWord)
      };

      const decrypt = CryptoJS.AES.decrypt(
        cipherParams,
        key,
        {
          mode: CryptoJS.mode.ECB,
          padding: CryptoJS.pad.Pkcs7
        }
      );

      return decrypt.toString(CryptoJS.enc.Utf8);
    } catch (e) {
      console.error("所有解密方法都失败", e);
      return '';
    }
  } catch (e) {
    console.error("AES解密错误:", e);
    return '';
  }
}

//密钥(长度必须为16位,或者16位的倍数)
export const encodeSecret = "1936+=--ckl;P,gj"

前端调用方式:

引入AES.js
import { aesDecrypt,aesEncrypt,encodeSecret } from '/utils/AES';

// 前端调接口传值前的加密
const data = {
	phone: formData.value.phonenumber,
	code: formData.value.captcha
};

const new_data = aesEncrypt(JSON.stringify(data), encodeSecret);
const new_form ={
	body:new_data
}


//解密的调用(后端对 res中的user对象进行了加密)
let user = aesDecrypt(res.user, encodeSecret)
console.log(user)

后端加解密工具类:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AESUtil {

    private static final String cKey = "1936+=--ckl;P,gj"; // 这里Key长度必须为16位

    // 加密
    public static String encrypt(String sSrc) throws Exception {
        byte[] raw = cKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
        return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
    }
    // 解密
    public static String decrypt(String sSrc) throws Exception {
        try {
            byte[] raw = cKey.getBytes("utf-8");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original, "utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

//    public static void main(String[] args) throws Exception {
//        /*
//         * 此处使用AES-128-ECB加密模式,key需要为16位。
//         */
//        // 需要加密的字串
//        String cSrc = "+nHGirm4nuxBebZu1ae4TQUxscfB0MzOJphHTyTwrhMsfWUNsfPzRzzdef1RPSM0pYVI17Vuk2TO9NoqPaWFQVqUDnSM1wahIGGBPR9uf3/C7/AgT40qGSlKO1H1sYQrztcT5Ev4BMeMJfZfVGUUMcdxtShXxGqomJfXC1m783Df1jtZD8DEndltsc6CCDejktm3XKyGrdLtev4atG5k3dUi2AwRI7wbj8G4unWH9lCxCVLj/Wny+lzMYFZvq3MV5lg4wnzVdUjG/q1KdT2QmLSyuGdKd3+s33brLJHn50q6ymD8y1IEo3bTNdjsj8TMNZ0Aabb8MaJ2bt/pvPZsG22Os95jYDiMaM4AOMT4KuD5G9PX2aATNx8CU1xVZ7/OVcyCxiGxd/N7nXnJ/651ggmH2vuCGyYXRMVKOIZYdYfrSJqPIqnRR5xXpRgBm7IsAfEFwxrSRc0EKBTbZE+BB9o793bTgJCpNlBVzdmx+W3mrJWapYBEJd6oRVNR7hm8PRSIZEnH2o2FPA3JBedsJjh0M/QolXleSo7KYHlm/1M=";
//        System.out.println(cSrc);
//        // 加密
//        String enString = AESUtil.Encrypt(cSrc, cKey);
//        System.out.println("加密后的字串是:" + enString);
//        // 解密
//        String DeString = AESUtil.decrypt(cSrc);
//        System.out.println("解密后的字串是:" + DeString);
//    }

}

后端调用加解密方式:

@ResponseBody
@PostMapping("/login")
public AjaxResult login(@RequestBody String body)
{
	AppUserLoginReq req = null;
	try {
		JSONObject bodyJOSN = JSON.parseObject(body);
		String decrypt = AESUtil.decrypt(bodyJOSN.getString("body"));
		req = JSON.parseObject(decrypt, AppUserLoginReq.class);
		// req即解密出来的对象(这里是针对前端传加密后的值对应body)
		
		// 这里省略了一些逻辑。。。。
		
		String token = loginService.appLogin(sysUser.getUserName());
		AjaxResult ajax = AjaxResult.success("登录成功");
		SysUser sysUser = userService.selectUserByPhone(req.getPhonenumber());
		// 这里相当于在前端返回的数据中对 res.user做了加密
		ajax.put("user", AESUtil.encrypt(JSON.toJSONString(sysUser)));
		return ajax;
	} catch (Exception e){
		return AjaxResult.error("参数异常");
	}
}


网站公告

今日签到

点亮在社区的每一天
去签到