uni-app和springboot完成前端后端对称加密解密流程

概述

  • 使用对称加密的方式实现。
  • 前端基于crypto-js。
  • uni-app框架中是在uni.request的基础上,在拦截器中处理的。
  • springboot在Filter中完成解密工作。

uni-app

  1. 项目中引入crypto-js。
npm install crypto-js
  1. 加密方法
const SECRET_KEY = CryptoJS.enc.Utf8.parse("1234123412341234");function encrypt (msg) {const dataHex = CryptoJS.enc.Utf8.parse(msg);const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
  1. 解密方法
function decrypt(msg) {const encryptedHexStr = CryptoJS.enc.Hex.parse(msg);const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return decrypt.toString(CryptoJS.enc.Utf8);
}
  1. request拦截器
uni.addInterceptor('request', {invoke(args) {let plaintext = JSON.stringify(args.data);plaintext = encodeURIComponent(plaintext);const textArray = [];while(plaintext.length > 15) {textArray.push(plaintext.substring(0, 16));plaintext = plaintext.substring(16);}textArray.push(plaintext);const encryptParamArray = [];textArray.forEach(item => {encryptParamArray.push(btoa(encrypt(item)));})args.data = {"encryptParams": encryptParamArray};},success(args) {}, fail(err) {}, complete(res) {}
});

备注

  • 使用encodeURIComponent方法是为了处理 字符“+”,这个对应java解密的时候存在问题。
  • 该模式默认解密长度出限制在16个字符中,所以需要将待加密的信息分解成单个字符长度小于16的字符组成数组。

Springboot

  1. DecryptFilter,解密拦截器
import cn.hutool.json.JSONUtil;
import org.apache.commons.codec.binary.Base64;
import org.springframework.http.HttpMethod;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;@WebFilter(urlPatterns = "/*") // 过滤所有请求
public class DecryptFilter implements Filter {private String word;public DecryptFilter(String word) {this.word = word;}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;if (HttpMethod.OPTIONS.matches(httpRequest.getMethod())) {filterChain.doFilter(httpRequest, servletResponse);return;}String encryptedData = "";if (httpRequest.getHeader("Content-Type").contains("x-www-form-urlencoded")) {// 获取请求参数或请求体中的加密数据encryptedData = httpRequest.getParameter("encryptParams");} else if (httpRequest.getHeader("Content-Type").contains("json")) {StringBuilder stringBuilder = new StringBuilder();try (InputStream inputStream = httpRequest.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {String line;while ((line = bufferedReader.readLine()) != null) {stringBuilder.append(line);}}encryptedData = JSONUtil.parseObj(stringBuilder.toString()).get("encryptParams").toString();encryptedData = encryptedData.replaceAll("[\\[\\]\"]", "");}String[] ciphertextArray = encryptedData.split(",");// 解密操作,例如使用AES解密String decryptedData = "";try {decryptedData = decrypt(ciphertextArray);} catch (Exception e) {throw new RuntimeException("解密失败!", e);}// 重构ServletRequest,将解密后的数据设置到新的ServletRequest中ServletRequest modifiedRequest = new BodyRewritingRequestWrapper(httpRequest, decryptedData);// 继续执行过滤器链filterChain.doFilter(modifiedRequest, servletResponse);}@Overridepublic void destroy() {}private String decrypt(String[] encryptedTextArray) throws Exception {StringBuilder paramsJson = new StringBuilder("");// 创建解密器Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");byte[] keyBytes = word.getBytes(StandardCharsets.UTF_8);SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");cipher.init(Cipher.DECRYPT_MODE, keySpec);for (String ciphertext : encryptedTextArray) {byte[] decode = java.util.Base64.getDecoder().decode(ciphertext);byte[] encryptedBytes = Base64.decodeBase64(decode);byte[] decryptedBytes = cipher.doFinal(encryptedBytes);paramsJson.append(new String(decryptedBytes, StandardCharsets.UTF_8));}return URLDecoder.decode(paramsJson.toString(), "UTF-8");}
}
  1. BodyRewritingRequestWrapper,重写的ServletRequest对相关
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;public class BodyRewritingRequestWrapper extends HttpServletRequestWrapper {private String body;private JSONObject map;public BodyRewritingRequestWrapper(HttpServletRequest request, String body) {super(request);this.body = body;this.map = JSONUtil.parseObj(body);}@Overridepublic String getParameter(String name) {if (map.containsKey(name)) {return map.get(name).toString();}return super.getParameter(name);}@Overridepublic Map<String, String[]> getParameterMap() {Map<String, String[]> originalParameters = super.getParameterMap();Map<String, String[]> rewriteMap = new HashMap<>(originalParameters);map.forEach((key, value) -> rewriteMap.put(key, new String[]{value.toString()}));return rewriteMap;}@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());return new ServletInputStream() {public int read() throws IOException {return byteArrayInputStream.read();}@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return true;}@Overridepublic void setReadListener(ReadListener readListener) {}};}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(this.getInputStream()));}
}
  1. 注册拦截器
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;@Configuration
public class WebConfig {@Value("${decrypt.word}")private String word;@Beanpublic FilterRegistrationBean<DecryptFilter> myFilterRegistration() {FilterRegistrationBean<DecryptFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new DecryptFilter(word));registration.addUrlPatterns("/*");registration.setName("decryptFilter");registration.setOrder(1);  // 设置过滤器的顺序,根据实际需求设置return registration;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/35444.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最强自动化测试框架Playwright(20)- iframe

一个页面可以附加一个或多个 Frame 对象。每个页面都有一个主框架&#xff0c;并且假定页面级交互&#xff08;如&#xff09;在主框架中运行。click frame_locator 使用 iframe 时&#xff0c;可以创建一个框架定位器&#xff0c;该定位器将进入 iframe 并允许选择该 iframe…

idea模板的使用(配置xml文件模板)

1. 问题的引出 我们在日常项目中可以发现&#xff0c;sql映射文件和mybatis主配置文件&#xff0c;以及application.yml文件中有很多固定不变的内容&#xff0c;为了方面使用&#xff0c;所以可以把这些xml文件设置为模板 2. 创建模板的步骤 按照图片一步一步进行即可 点击…

gcc编译选项之预处理向源码传参和条件编译

一、是什么? 预处理:是指在进行加工前准备工作. gcc 选项 文件名字 二、使用步骤 1.向源码传参 gcc -save-temps -DSENSOR_TYPE=SONY_IMX477_MIPI_8M_30FPS_12BIT hello.c -o hello 代码如下(示例): #include <stdio.h> #include <stdlib.h>typedef enum …

acwing 平衡括号字符串 贪心 括号序列

&#x1f468;‍&#x1f3eb; 平衡括号字符串 给定一个字符串 s s s&#xff0c;该字符串的每个字符都是 (、) 或 # 之一。 你的任务是将 s s s 中的每个 # 变换为一个或多个 )&#xff0c;从而得到一个平衡括号字符串。 不同 # 变换的 ) 的数量可以不同。 请你输出为了…

数据容器——元组(tuple)

1、元组与列表的不同点 列表是可以修改的。如果想要传递的信息&#xff0c;不被算改&#xff0c;列表就不合适了。 元组同列表一样&#xff0c;都是可以封装多个、不同类型的元素在内。 但最大的不同点在于&#xff1a;元组一旦定义完成&#xff0c;就不可修改 所以&#xff…

2023河南萌新联赛第(五)场:郑州轻工业大学 --01分数规划

题目描述 给定一个字符串 s&#xff0c;仅含 0, 1, ? 三种字符&#xff0c;你必须将所有 ? 替换为 1 或 0 。 定义 s 的美好值为将所有?进行替换后&#xff0c;s的最长连续 1 或 0 的子串的长度。请你进行所有替换后&#xff0c;使得字符串 s 的美好值最大&#xff0c;请输…

(二)结构型模式:1、适配器模式(Adapter Pattern)(C++实现示例)

目录 1、适配器模式&#xff08;Adapter Pattern&#xff09;含义 2、适配器模式应用场景 3、适配器模式的UML图学习 4、C实现适配器模式的示例 1、适配器模式&#xff08;Adapter Pattern&#xff09;含义 将一个接口转换为客户端所期待的接口&#xff0c;从而使两个接口…

CompletableFuture

java8中新引入了批量线程处理类CompletableFuture CompletableFuture.allOf是与的关系, 每个都要执行完 CompletableFuture.anyOf是或的关系, 其中一个执行完 以下示例代码: CompletableFuture.allOf(CompletableFuture.runAsync(() -> {Thread.currentThread().setName(&q…

js常用的方法函数

JavaScript 中有许多常用的内置方法和函数&#xff0c;用于处理字符串、数组、对象、日期等不同类型的数据。以下是一些常见的 JavaScript 方法和函数&#xff1a; 字符串操作&#xff1a; str.length: 返回字符串的长度。 str.charAt(index): 返回指定位置的字符。 str.indexO…

Mac安装nvm教程及使用

nvm 是 node 版本管理器&#xff0c;也就是说一个 nvm 可以管理多个 node 版本&#xff08;包含 npm 与 npx&#xff09;&#xff0c;可以方便快捷的安装、切换 不同版本的 node。 1、直接通过brew安装 执行命令&#xff1a;brew install nvm PS&#xff1a; 如果没有安装br…

Golang - 生成和读取toml文件

代码示例&#xff1a; package mainimport ("fmt""github.com/pelletier/go-toml""os""path" )func CreateToml(tomlPath string) {tree, err : toml.Load("")if err ! nil {fmt.Println("Error while creating empt…

Oracle database 静默安装 oracle 11g 一键安装

基于oracle安装包中应答文件实现一键安装 支持环境&#xff1a; Linux &#xff1a;centerOS 7 oracle &#xff1a;11.2.0 Oracle应答文件 runInstaller应答文件 /database/response/db_install.rsp netca应答文件 /database/response/netca.rsp dbca应答文件 /database/re…

小程序保留2位小数据,不四舍五入

方法1&#xff1a; parseInt toFixed /* * 保留2位小数&#xff0c;不四舍五入 * 5.992550 >5.99 , 2 > 2.00 * */ const toFixed2Decimal (value) > {return (parseInt(value*100)/100).toFixed(2) } console.log(587.67*100) console.log(toFixed2Decimal(587.67…

python中的运算符号含义,python基本运算符的操作

本篇文章给大家谈谈python的运算符号有哪些类型&#xff0c;以及python各运算符号的功能说明&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 1.算数运算符&#xff08;最常见的&#xff09; 标准算数运算符&#xff08;加减乘除&#xff09; 取余运算…

(provider: SSL Provider, error: 0 - 证书链是由不受信任的颁发机构颁发的。)

问题描述 NET6 Code First 使用Update-database时 报错&#xff1a;A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - 证书链是由不受信任的颁发机构颁发的。) 解决方…

UML-状态图

目录 状态图 状态图的图符 状态机 状态 ​转换 电话机状态图 活动图和状态图区别&#xff1a; 状态图 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为&#xff0c;显示了该实体如何根据当前所处的状态对不同的事件做出反应。通常我们创建一个UML状态…

Jmeter设置中文的两种方式,建议使用第二种

方案一 进入jmeter图像化界面&#xff0c;选择Options下的Choose Language&#xff0c;再选择Chinese(Simplified)。这个就是选择语言为简体中文&#xff08;缺陷&#xff1a;这个只是在本次使用时为中文&#xff0c;下次打开默认还是英文的&#xff09; 方案二&#xff08;…

Mybatis框架

Mybatis框架 Mybatis的含义&#xff1a;Mybatis框架是一个持久层框架&#xff0c;几乎解决了jdbc代码在手动设置参数和对结果集的手动获取问题&#xff0c;原本是apache公司的开源项目&#xff0c;最后转给Google公司。Mybatis会将参数封装在一个对象中传递给数据库&am…

数学建模(二)线性规划

课程推荐&#xff1a;6 线性规划模型基本原理与编程实现_哔哩哔哩_bilibili 目录 一、线性规划的实例与定义 1.1 线性规划的实例 1.2 线性规划的定义 1.3 最优解 1.4 线性规划的Mathlab标准形式 1.5 使用linprog函数 二、线性规划模型建模实战与代码 2.1 问题提出 2.2…

机器学习深度学习——seq2seq实现机器翻译(详细实现与原理推导)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——seq2seq实现机器翻译&#xff08;数据集处理&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习&…