针对客户对数据交互过程中的加密要求,防止直接的数据爬取,对前后端数据请求时的返回数据进行数据的加密。实用性嘛,也就那样了,代码可直接适配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文章来源:https://www.toymoban.com/news/detail-697983.html
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模板网!