# 实现请求可配置是否加密接口
毫无疑问,系统数据安全以及防止接口被随意调用破解,接口请求参数及返回数据进行加密显得尤为重要。那如何实现呢?
既然涉及到了请求数据加密,以及相应数据加密,那当然需要后端配合啦。具体逻辑
前端将请求数据加密发送请求
——》
后端根据前端加密对应的解密逻辑对数据进行解密后执行相应操作,将数据加密,给前端响应
——》
前端根据后端加密对应的解密逻辑对数据进行解密后执行相应操作
上代码
# 第一步:安装 crypto-js
npm install crypto-js@^4.0.0 -S
# 第二步:新建文件,定义好加密及解密方法
var CryptoJS = require("crypto-js");
const config = {
// 秘钥 可自定义
secret: "关注微信公众号【爆米花小布】不迷路",
}
//对象加密方法
export function encryptObj(reqData) {
return CryptoJS.AES.encrypt(JSON.stringify(reqData), config.secret).toString()
}
//对象解密方法
export function decryptObj(resData) {
const bytes = CryptoJS.AES.decrypt(resData, config.secret)
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
}
//字符串加密方法
export function encryptStr(reqData) {
return CryptoJS.AES.encrypt(reqData + "", config.secret).toString()
}
//字符串解密
export function decryptStr(resData) {
const bytes = CryptoJS.AES.decrypt(resData, config.secret)
return bytes.toString(CryptoJS.enc.Utf8);
}
# 第三步:axios配置请求拦截及响应拦截中添加逻辑
import axios from "axios"
import Message from "@/plugins/reset-message.js"
import store from "@/store"
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_URL,
timeout: process.env.VUE_APP_TIME_OUT // 请求超时时间
})
// request拦截器
service.interceptors.request.use(
config => {
const token = getToken()
if (token) {
config.headers.Authorization = "Bearer " + token
}
// 如果存在config.data 则为对象加密方式
if (config.data) {
config.data = {
encryptData: encryptObj(config.data)
}
}
// 如果为params 由于此时参数是挂在url后面的,因此不能整个对象一起加密,得单独对有值的加密
if (config.params) {
for (const key in config.params) {
if (config.params[key] !== "" && config.params[key] !== null && config.params[key] !== undefined) {
config.params[key] = encryptStr(config.params[key])
}
}
}
return config
},
error => {
Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
async response => {
const res = response.data
// 对后端返回的数据进行解密
res.data = decryptObj(res.data)
// 如果自定义代码不是200,则判断为错误。
if (response.status !== 200) {
Message({
message: res.message || "Error",
type: "error",
duration: 5 * 1000
})
return Promise.reject(new Error(res.message || "Error"))
} else {
// code为200 或 返回的是文件流 直接返回
if (res.code === 200 || response.config.responseType === "blob") {
return res
}
Message({
message: res.message || "Error",
type: "error",
duration: 5 * 1000
})
if (res.code === 401) {
await store.dispatch("user/logout")
window.location.reload()
}
return Promise.reject(new Error(res.message || "Error"))
}
},
error => {
if (error.name === "AxiosError") {
Message.error(error.message)
}
return Promise.reject(new Error(error))
}
)
export default service
上述处理后,要求后端也进行相应处理,都处理后 此时所有接口都已经进行了加密处理,但是存在个问题——部分以formdata方式请求的接口是无法进行加密的(可能可以加密,我不知道而已),因此需要能配置接口是否需要加密
# 第四步:配置接口需要加密
/**
* @description: 登录
* @param {*}
* @return {*}
* @author: syx
*/
export function login(data = {}, config = {
encryption: true
}) {
return axiosRequest.post("/xiaobu-admin/login", data, config)
}
# 第五步:在axios请求配置加解密中添加条件
import axios from "axios"
import Message from "@/plugins/reset-message.js"
import store from "@/store"
// 系统配置 是否 加密 此处请看下一篇文章 配置全局变量
const encryption = window.configObj.encryption || process.env.VUE_APP_ENCRYPTION
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_URL,
timeout: process.env.VUE_APP_TIME_OUT // 请求超时时间
})
// request拦截器
service.interceptors.request.use(
config => {
const token = getToken()
if (token) {
config.headers.Authorization = "Bearer " + token
}
// 不是formData格式数据 且 返回类型不是 blob 文件流 才进行加密
const canEncryption = !((config.data instanceof FormData) || (config.responseType&&config.responseType.toLocaleLowerCase() === "blob"))
//加密接口 系统配置可加密 且接口配置也加密 才进行加密
if (encryption === "1" && config.encryption && canEncryption) {
// 与后端约定,在请求头添加是否加密标识符
config.headers.encrypt = "1"
if (config.data) {
config.data = {
encryptData: encryptObj(config.data)
}
}
if (config.params) {
for (const key in config.params) {
if (config.params[key] !== "" && config.params[key] !== null && config.params[key] !== undefined) {
config.params[key] = encryptStr(config.params[key])
}
}
}
}
return config
},
error => {
Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
async response => {
const res = response.data
//如果系统配置可加密 且接口配置可加密 且返回数据类型不是文件流
if (encryption === "1" && response.config.encryption && response.config.responseType !== "blob") {
res.data = decryptObj(res.data)
}
// 如果自定义代码不是200,则判断为错误。
if (response.status !== 200) {
Message({
message: res.message || "Error",
type: "error",
duration: 5 * 1000
})
return Promise.reject(new Error(res.message || "Error"))
} else {
// code为200 或 返回的是文件流 直接返回
if (res.code === 200 || response.config.responseType === "blob") {
return res
}
Message({
message: res.message || "Error",
type: "error",
duration: 5 * 1000
})
if (res.code === 401) {
await store.dispatch("user/logout")
window.location.reload()
}
return Promise.reject(new Error(res.message || "Error"))
}
},
error => {
if (error.name === "AxiosError") {
Message.error(error.message)
}
return Promise.reject(new Error(error))
}
)
export default service
WARNING
FormData请求格式不支持加密。
这是需要前后端配合约定的优化,提前与后端约定好标识符。
如果对于大多数接口都需要进行加密的,可默认全部加密,对部分接口进行配置不加密,反之则同理。
# 总结
此篇文章为axios请求优化其二,关于对接口进行加密处理的配置,关注微信公众号【爆米花小布】不迷路。如有问题,可私信。