SpringBoot+Vue 后端输出加密,前端请求统一解密

这篇具有很好参考价值的文章主要介绍了SpringBoot+Vue 后端输出加密,前端请求统一解密。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

针对客户对数据交互过程中的加密要求,防止直接的数据爬取,对前后端数据请求时的返回数据进行数据的加密。实用性嘛,也就那样了,代码可直接适配Ruoyi SpringBoot+vue项目,具体加密方式和处理仅供参考!

前端

request.js

import axios from 'axios'
import { Notification, MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'

import DES from './des'

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  baseURL: process.env.VUE_APP_BASE_API,
  // 超时
  timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
  // console.log(config);
  // 是否需要设置 token
  const isToken = (config.headers || {}).isToken === false
  if (getToken() && !isToken) {
    config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
  }
  // get请求映射params参数
  if (config.method === 'get' && config.params) {
    let url = config.url + '?';
    for (const propName of Object.keys(config.params)) {
      const value = config.params[propName];
      var part = encodeURIComponent(propName) + "=";
      if (value !== null && typeof (value) !== "undefined") {
        if (typeof value === 'object') {
          for (const key of Object.keys(value)) {
            if (value[key] !== null && typeof (value[key]) !== 'undefined') {
              let params = propName + '[' + key + ']';
              let subPart = encodeURIComponent(params) + '=';
              url += subPart + encodeURIComponent(value[key]) + '&';
            }
          }
        } else {
          url += part + encodeURIComponent(value) + "&";
        }
      }
    }
    url = url.slice(0, -1);
    config.params = {};
    config.url = url;
  }
  return config
}, error => {
  console.log(error)
  Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use(res => {
    // 未设置状态码则默认成功状态
    const code = res.data.code || 200;
    // 获取错误信息
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    if (code === 401) {
      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).then(() => {
        store.dispatch('LogOut').then(() => {
          location.href = '/index';
        })
      }).catch(() => { });
      return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
    } else if (code === 500) {
      Message({
        message: msg,
        type: 'error'
      })
      return Promise.reject(new Error(msg))
    } else if (code !== 200) {
      Notification.error({
        title: msg
      })
      return Promise.reject('error')
    } else {

      console.log(res.data);

      // DES解密
      if (res.data.result) {
        let decrypt = DES.decryptECB(res.data.result, '947dcfd3-1163-4ad7-b0f9-b68a78434406')
        if(res.data.hasOwnProperty("rows")){
          res.data.rows = JSON.parse(decrypt)
        }else{
          res.data.data = JSON.parse(decrypt)
        }
        delete res.data['result']
      }

      return res.data
    }
  },
  error => {
    console.log('err' + error)
    let { message } = error;
    if (message == "Network Error") {
      message = "后端接口连接异常";
    }
    else if (message.includes("timeout")) {
      message = "系统接口请求超时";
    }
    else if (message.includes("Request failed with status code")) {
      message = "系统接口" + message.substr(message.length - 3) + "异常";
    }
    Message({
      message: message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

des.js

import CryptoJS from 'crypto-js'

export default {
    // 加密
    encryptECB(text, textKey) {
        //把私钥转换成16进制的字符串
        var key = CryptoJS.enc.Utf8.parse(textKey);
        //模式为ECB padding为Pkcs7
        var encrypted = CryptoJS.DES.encrypt(text, key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        });
        //加密出来是一个16进制的字符串
        return encrypted.ciphertext.toString();

    },

    // 解密
    decryptECB(ciphertext, textKey) {
        //把私钥转换成16进制的字符串
        var key = CryptoJS.enc.Utf8.parse(textKey);
        console.log(123, key);
        // console.log(CryptoJS.enc.Utf8.stringify(key));
        //把需要解密的数据从16进制字符串转换成字符byte数组
        var decrypted = CryptoJS.DES.decrypt({
            ciphertext: CryptoJS.enc.Hex.parse(ciphertext)
        }, key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        });
        //以utf-8的形式输出解密过后内容
        return decrypted.toString(CryptoJS.enc.Utf8);
    }
}

后端java文章来源地址https://www.toymoban.com/news/detail-697983.html

package com.silen.framework.aspect;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 只有使用了该注解的方法才需要执行AES解密
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DESDecrypt { }
package com.silen.framework.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.silen.common.config.SilenConfig;
import com.silen.common.core.domain.AjaxResult;
import com.silen.common.core.page.TableDataInfo;
import com.silen.framework.aspect.utils.Constant;
import com.silen.framework.aspect.utils.DESUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Controller AES加密:针对所有请求的返回结果进行加密
 */
@Aspect
@Order(2)
@Component
public class DESEncryptAspect {

    @Pointcut("execution(* com.silen.*.controller..*.*(..))")
    public void pointcut() {}

    @Around("pointcut()")
    @SuppressWarnings("unchecked")
    public Object decrypt(ProceedingJoinPoint point) throws Throwable {
        // 获取到控制器返回结果
        Object proceed = point.proceed(point.getArgs());
        if(proceed instanceof AjaxResult){
            AjaxResult r = (AjaxResult) proceed;
            // 如果包含结果集,将结果集进行加密后返回
            if (r.containsKey("data")) {
                Object json = r.get("data");
                String encrypt = DESUtil.encode(Constant.DES_KEY,JSON.toJSONString(json));
                //String encrypt = AESUtil.AESEncrypt(JSON.toJSONString(json));
                r.remove("data");
                r.put(Constant.SUCCESS_NAME, encrypt);
            }
            return r;
        }else if(proceed instanceof TableDataInfo){
            TableDataInfo r =(TableDataInfo)proceed;
                List<?> rows = r.getRows();
            String encrypt = DESUtil.encode(Constant.DES_KEY, JSON.toJSONString(rows));
            r.setRows(new ArrayList<>());
            r.setResult(encrypt);
            return r;
        }
        return proceed;
    }

}
package com.silen.framework.aspect;

import com.alibaba.fastjson.JSON;
import com.silen.framework.aspect.exception.DESException;
import com.silen.framework.aspect.exception.TypeConverterException;
import com.silen.framework.aspect.utils.Constant;
import com.silen.framework.aspect.utils.DESUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.HashMap;

/**
 * Controller AES解密:GET、DELETE请求
 *    由于AESOtherDecryptAspect实现的RequestBodyAdvice只针对拥有请求体的HTTP请求生效
 *    而GET、DELETE请求不包含请求体,所以这里单独使用AOP进行解密
 */
@Aspect
@Order(1)
@Component
public class DESGetDeleteDecryptAspect {

    // 切入点:只有使用了@DESDecrypt注解的GET请求才会执行解密
    @Pointcut("@annotation(com.silen.framework.aspect.DESDecrypt) && " +
            "(@annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.DeleteMapping)) && " +
            "execution(* com.silen.*.controller..*.*(..))")
    public void pointcut() { }

    @Around("pointcut()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取到请求的参数列表进行解密
        Object[] args = joinPoint.getArgs();
        this.decrypt(args);
        // 执行将解密的结果交给控制器进行处理,并返回处理结果
        return joinPoint.proceed(args);
    }

    // 解密方法
    @SuppressWarnings("unchecked")
    public void decrypt(Object[] args) throws DESException, TypeConverterException {
        // 获取请求参数并转换为字符串(密文)
        HashMap<String, Object> data = (HashMap<String, Object>) args[0];
        String encrypt = data.get("json").toString();
        // 将密文解密为JSON字符串
        String json = DESUtil.decode(Constant.DES_KEY,encrypt);
        // 将JSON字符串转换为Map集合,并替换原本的参数
        args[0] = JSON.parse(json);
    }

}
package com.silen.framework.aspect;

import com.alibaba.fastjson.JSON;
import com.silen.framework.aspect.utils.Constant;
import com.silen.framework.aspect.utils.DESUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.HashMap;

/**
 * Controller AES解密:POST、PUT请求
 *    1. 使用@ControllerAdvice注解扫描Controller所在位置
 *    2. 实现RequestBodyAdvice接口来处理参数
 *
 *    经测试:RequestBodyAdvice执行优先级高于AOP
 */
@ControllerAdvice("com.silen.*.controller")
public class DESPostPutDecryptAspect implements RequestBodyAdvice {

    // 判断当前Controller是否需要进行参数解密
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        // 只有标识了@DESDecrypt注解的控制器才需要解密
        return methodParameter.hasMethodAnnotation(DESDecrypt.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        return new HttpInputMessage() {
            @Override
            public InputStream getBody() throws IOException {
                String json = null;
                try {
                    InputStream body = httpInputMessage.getBody();
                    HashMap<String, Object> map = (HashMap<String, Object>) JSON.parse(IOUtils.toString(body));
                    String encrypt = map.get("json").toString();
                     json = DESUtil.decode(Constant.DES_KEY,encrypt);
                } catch (Exception e) {
                    // TODO 异常处理待考究
                }
                return IOUtils.toInputStream(json);
            }
            @Override
            public HttpHeaders getHeaders() {
                return httpInputMessage.getHeaders();
            }
        };
    }

    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return o;
    }

    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return o;
    }

}
package com.silen.framework.aspect.exception;

/**
 * AES数据加密解密异常
 */
public class DESException extends Exception {

    public DESException(String msg) {
        super(msg);
    }

}
package com.silen.framework.aspect.exception;

/**
 * 类型转换异常
 */
public class TypeConverterException extends Exception{

    public TypeConverterException(String msg) {
        super(msg);
    }

}
package com.silen.framework.aspect.utils;

import javax.crypto.Cipher;
import java.security.Key;

/**
 * 加密协议工具
 */
public class DESUtil {

    private static String strDefaultKey = "mykey";
    private Cipher encryptCipher = null;
    private Cipher decryptCipher = null;

    public static String byteArr2HexStr(byte[] arrB) throws Exception {
        int iLen = arrB.length;
        StringBuffer sb = new StringBuffer(iLen * 2);
        for (int i = 0; i < iLen; i++) {
            int intTmp = arrB[i];
            while (intTmp < 0) {
                intTmp = intTmp + 256;
            }
            if (intTmp < 16) {
                sb.append("0");
            }
            sb.append(Integer.toString(intTmp, 16));
        }
        return sb.toString();
    }

    public static byte[] hexStr2ByteArr(String strIn) throws Exception {
        byte[] arrB = strIn.getBytes();
        int iLen = arrB.length;

        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;
    }

    public DESUtil() throws Exception {
        this(strDefaultKey);
    }

    public DESUtil(String strKey) throws Exception {
        if (strKey == null)
            return;
        java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
        Key key = getKey(strKey.getBytes());
        encryptCipher = Cipher.getInstance("DES");
        encryptCipher.init(Cipher.ENCRYPT_MODE, key);

        decryptCipher = Cipher.getInstance("DES");
        decryptCipher.init(Cipher.DECRYPT_MODE, key);
    }

    public void renderKey(String strKey) throws Exception {
        if (strKey == null)
            return;
        java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
        Key key = getKey(strKey.getBytes());
        encryptCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        encryptCipher.init(Cipher.ENCRYPT_MODE, key);

        decryptCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        decryptCipher.init(Cipher.DECRYPT_MODE, key);
    }

    public byte[] encrypt(byte[] arrB) throws Exception {
        return encryptCipher.doFinal(arrB);
    }

    public String encrypt(String strIn) throws Exception {
        return byteArr2HexStr(encrypt(strIn.getBytes()));
    }


    public byte[] decrypt(byte[] arrB) throws Exception {
        return decryptCipher.doFinal(arrB);
    }

    public String decrypt(String strIn) throws Exception {
        return new String(decrypt(hexStr2ByteArr(strIn)));
    }


    private Key getKey(byte[] arrBTmp) throws Exception {
        byte[] arrB = new byte[8];

        for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
            arrB[i] = arrBTmp[i];
        }

        Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");

        return key;
    }


    /**
     * 加密
     *
     * @param key 密钥
     * @param str 需要加密的字符串
     * @return
     */
    public static String encode(String key, String str) {
        DESUtil des = null;
        try {
            des = new DESUtil(key);
            return des.encrypt(str);
        } catch (Exception ex) {
        }
        return "";
    }

    public static String decode(String key, String str) {
        DESUtil des = null;
        try {
            des = new DESUtil(key);
            return des.decrypt(str);
        } catch (Exception ex) {
        }
        return "";
    }
    public static String decode(String key, String str,String charset) {
        DESUtil des = null;
        try {
            des = new DESUtil(key);
            return des.decrypt(str,charset);
        } catch (Exception ex) {
        }
        return "";
    }
    public String decrypt(String strIn,String charset) throws Exception {
        return new String(decrypt(hexStr2ByteArr(strIn)),charset);
    }
}

到了这里,关于SpringBoot+Vue 后端输出加密,前端请求统一解密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java和js实现前端加密后端解密,后端加密前端解密(Base64)

    目录 1.前端加密后端解密 2.后端加密前端解密 在前端和后端数据传输时,常常涉及到隐私数据的传输(例如用户名和密码),这时,我们就需要对隐私数据进行加密解密 1.前端加密后端解密         1.1 前端jquery实现         1.2后端 2.后端加密前端解密         2.1后端加密

    2024年02月16日
    浏览(59)
  • RSA之前端加密后端解密

    RSA加密解密方式有: (1)公钥加密,私钥解密; (2)私钥加密,公钥解密; 此文章中以下我使用的是 前端公钥加密,后端私钥解密 ; http://web.chacuo.net/netrsakeypair 生成对应的公钥和私钥 前端加密js文件 : 链接: https://pan.baidu.com/s/1NIMayTcmjbMOf7BqPhPQoA 提取码: t7an 下载js文件并

    2024年02月21日
    浏览(54)
  • 使用非对称加密(RSA) 实现前端加密后端解密

    数据加密方式有: 单向加密、对称加密、非对称加密、加密盐、散列函数、数字签名。 1、单向加密 单向加密通过对数据进行摘要计算生成密文,密文不可逆推还原。只能加密,不能解密,常用于提取数据的指纹信息以此来验证数据的完整性。但是会引发雪崩效应(雪崩效应

    2024年02月08日
    浏览(69)
  • AES对称加密实战——前端js加密后端python解密

    高级加密标准(AES, Advanced Encryption Standard),是一种最常见的对称加密算法 。其加密流程如下图所示,发送方通过密钥对明文加密后进行网络传输,接收方用同样的密钥将密文解密。在前后端通讯场景中,可利用AES算法对用户密码进行加密后传输,防止被抓包而造成密码泄露。

    2024年02月04日
    浏览(61)
  • 前端AES加密,后端解密,有效防止数据外泄

    在工作中经常遇到密码明文传输这个问题,为了让密码安全些会让加密,现在有个比较方便的AES加密(前端密钥可能存在泄露风险,应该放到配置项中): 一、前端加密 1、首先引入前端需要用到的js:crypto-js,下载地址: CryptoJS-v4.1.1 https://www.aliyundrive.com/s/bXP6M8ZxVAD 点击链接

    2024年02月16日
    浏览(51)
  • vue2前端使用axios发起post请求,后端(springboot)拿不到值解决办法

    axios封装-我常用的请求头参数  application/json; charset=utf-8 页面登录请求-post 网络请求正常传入参数 后端代码,查看控制台发现都为null,没取到值。 1.尝试将前端post请求改成get,其他都不用变 发现正常取到值,打印输出正常。前端页面正常跳转。 2.后端设置为post请求,前端a

    2024年02月02日
    浏览(50)
  • 三步实现Java的SM2前端加密后端解密

    秦医如毒,无药可解。 话不多说,先上需要用到的 js文件下载链接   和   jsp前端代码 。 第一步: 下载两个必备的js文件——  crypto-js.js 、 sm2.js   。 它们的下载链接如下↓(该网页不魔法上网的话会很卡,毕竟github,建议卡的话就多重新加载几次,我差不多试了8次才进

    2024年02月04日
    浏览(53)
  • 使用CryptoJS实现Vue前端加密,Java后台解密的步骤和方法

    1、crypto.js简介   CryptoJS 是一个 JavaScript 库,提供了一系列密码学函数和工具,用于加密、解密、生成摘要等任务。它支持多种加密算法,包括常见的对称加密算法(如 AES、DES)和非对称加密算法(如 RSA)。   同时,CryptoJS还包括了ECB和CBC两种模式,其中 ECB模式 :全称

    2024年02月04日
    浏览(62)
  • 前端VUE后端JAVA,SM2加解密,一篇解决你的问题

    1、后端加密后密文前两位为“04”,前端解密不了,所以在前端解密时要把“04”去掉, 2、前端加密后,密文没有“04”,所以前端加密完要在密文前面加上“04”

    2024年04月23日
    浏览(38)
  • springboot + vue 前后端加密传输 RSA互相加解密、加签验签、密钥对生成

    参考 由于Java非对称加解密、加验签都是采用PKCS#8格式的密钥,PKCS#1格式的密钥跑不通,这里先简单介绍一下两者的区别。 PKCS#1和PKCS#8是两个不同的数字证书标准。 PKCS#1是一个公钥加密标准,它定义了使用RSA算法进行加密和签名的格式。主要用于对数字签名、加密以及数字签

    2024年04月27日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包