Spring 接口参数加密传输
加密方式 AES
spring jar 包 pom.xml配置(注意版本)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.5.RELEASE</version>
<scope>test</scope>
</dependency>
这个是原理图
在spring做如下 配置。
<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="com.sifude.youlife.spring.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonHttpMessageConverter" />
<ref bean="stringHttpMessageConverter" />
<!-- <ref bean="marshallingHttpMessageConverter" /> -->
</list>
</property>
</bean>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
<property name="supportedMediaTypes">
<value>text/html;charset=UTF-8</value>
</property>
</bean>
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
可以发现com.sifude.youlife.spring.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter这个类就是我们自己写的。从spring里面拷贝出如下几个类
RequestParamMethodArgumentResolver对每个参数进行了拦截,然后在resolveName方法进行处理,因此我们只要
重写RequestParamMethodArgumentResolver中的resolveName方法即可
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
Object arg;
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
if (MultipartFile.class.equals(parameter.getParameterType())) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFile(name);
}
else if (isMultipartFileCollection(parameter)) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFiles(name);
}
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
assertIsMultipartRequest(servletRequest);
arg = servletRequest.getParameter(name);
}
else {
arg = null;
if (multipartRequest != null) {
List<MultipartFile> files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
boolean isEnc = false;
if (null != parameter.getMethod().getAnnotation(EncRequest.class)) {
isEnc = true;
}
if (isEnc) {// 数据需要加密的情况
String content = servletRequest.getParameter("content");
if (null != content) {
content = AESUtil.decrypt(content);
ObjectMapper mapper = new ObjectMapper(); // can reuse, share
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 忽略未知元素
Object o = mapper.readValue(content, HashMap.class).get(name);
if(o instanceof String[]) {
String[] paramValues = (String[]) o;
if (paramValues != null) {
arg = paramValues.length == 1 ? paramValues[0] : paramValues;
}
} else {
arg = o;
}
}
} else {
String[] paramValues = webRequest.getParameterValues(name);
if (paramValues != null) {
arg = paramValues.length == 1 ? paramValues[0] : paramValues;
}
}
}
}
return arg;
}
其他1个注解和加密算法
package com.sifude.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncRequest {
}
package com.sifude.tool.util;
import java.io.UnsupportedEncodingException;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sifude.tool.util.entity.Constant;
/**
* AES加解密算法
* key:每次登陆动态随机生成(大小写字母和数字组成),并保存在session中
* 此处使用AES-128-CBC加密模式,key需要为16位
*/
public class AESUtil {
private static Logger log = LoggerFactory.getLogger(FileUtil.class);
public static boolean isAES = Constant.AES.ISAES;
public static String sKey = Constant.AES.SKEY;
// 加密
public static String encrypt(String sSrc) throws Exception {
if(!isAES) {
return sSrc;
}
if (sKey == null) {
//System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
//System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
//加密前要进行编码,否则js无法解码
byte[] encrypted = cipher.doFinal(sSrc.getBytes("UTF-8"));
return Base64.encodeBase64String(encrypted);// 此处使用BAES64做转码功能,同时能起到2次加密的作用。
}
// 解密
public static String decrypt(String sSrc) throws Exception {
if(!isAES) {
return sSrc;
}
// 判断Key是否正确
if (sKey == null) {
//System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
//System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes("ASCII");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("0102030405060708"
.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = Base64.decodeBase64(sSrc);// 先用bAES64解密
//System.out.println(encrypted1.length);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
}
// 生成随机密锁
public static String getKey(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
// 参数length,表示生成几位随机数
for (int i = 0; i < length; i++) {
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
// 输出字母还是数字
if ("char".equalsIgnoreCase(charOrNum)) {
// 输出是大写字母还是小写字母
int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
sb.append((char) (random.nextInt(26) + temp));
} else if ("num".equalsIgnoreCase(charOrNum)) {
sb.append(String.valueOf(random.nextInt(10)));
}
}
try {
return new String(sb.toString().getBytes(), "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
}
return "mapabc2014214yxj";
}
public static void main(String[] args) {
//AES.sKey = getKey(16);
AESUtil.isAES = true;
try {
//String str = AES.encrypt("你好1.2#3:4//5_6,1 2&3?4a/bc5=6");
//String str = AES.encrypt("{\"account\":\"ez\",\"password\":\"123456\"}");
String str = AESUtil.encrypt("{\"cityId\":\"110000\",\"cityType\":\"1\"}");
System.out.println(str);
String str1 = AESUtil.decrypt(str);
System.out.println(str1);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
这样功能就实现了,欢迎大家一期交流。
Spring 接口参数加密传输的更多相关文章
- 如何写出安全的API接口?接口参数加密签名设计思路
开发中经常用到接口,尤其是在面向服务的soa架构中,数据交互全是用的接口. 几年以前我认为,我写个接口,不向任何人告知我的接口地址,我的接口就是安全的,现在回想真是too young,too simp ...
- 如何写出安全的 API 接口?接口参数加密签名设计思路
原文链接:http://blog.csdn.net/ma_jiang/article/details/53636840
- 如何写出安全的API接口(参数加密+超时处理+私钥验证+Https)- 续(附demo)
上篇文章说到接口安全的设计思路,如果没有看到上篇博客,建议看完再来看这个. 通过园友们的讨论,以及我自己查了些资料,然后对接口安全做一个相对完善的总结,承诺给大家写个demo,今天一并放出. 对于安全 ...
- 基于RequestBodyAdvice和ResponseBodyAdvice来实现spring中参数的加密和解密
在日常开发中,有时候我们经常需要和第三方接口打交道,有时候是我们调用别人的第三方接口,有时候是别人在调用我们的第三方接口,那么为了调用接口的安全性,一般都会对传输的数据进行加密操作,如果每个接口都由我 ...
- 分享如何使用PHP将URL地址参数进行加密传输提高网站安全性
大家在使用PHP进行GET或POST提交数据时,经常会在URL带着参数进行传递,比如www.mdaima.com/get.php?id=1&page=5,这里就将id编号和page页码进行了参 ...
- Spring Boot 之:接口参数校验
Spring Boot 之:接口参数校验,学习资料 网址 SpringBoot(八) JSR-303 数据验证(写的比较好) https://qq343509740.gitee.io/2018/07/ ...
- java 调用Spring接口上传文件及其他参数填充
第一步:在Spring配置中添加以下内容 <!-- 配置MultipartResolver 用于文件上传 使用spring的CommosMultipartResolver --> < ...
- spring 接口校验参数(自定义注解)
1. 注解类 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.l ...
- Spring Boot实现通用的接口参数校验
Spring Boot实现通用的接口参数校验 Harries Blog™ 2018-05-10 2418 阅读 http ACE Spring App API https AOP apache IDE ...
随机推荐
- 如果没有<form>标签,也没有enctype="multipart/form-data"属性,怎么使用formData对象提交表单呢?如下方式
form标签的enctype属性 enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码. 默认地,表单数据会编码为 "application/x-www-form-urlen ...
- JSONP方法简单封装
function myJsonp(url, data, callback) { //参数判断 if (Object.prototype.toString.call(data) == "[ob ...
- JS监听浏览器的返回、后退、上一页按钮的事件方法
在实际的应用中,我们常常需要实现在移动app和浏览器中点击返回.后退.上一页等按钮实现自己的关闭页面.调整到指定页面或执行一些其它操作的需求,那在代码中怎样监听当点击微信.支付宝.百度糯米.百度钱包等 ...
- VMware与Hyper-V的冲突解决 VMware Workstation 与 Device/Credential Guard 不兼容 解决方案
win10专业版官方解决方案https://kb.vmware.com/s/article/2146361 win10家庭版解决方案win10家庭版本身是不支持Hyper-V服务的,但是如果是“win ...
- QT安装后再添加或删除组件
QT安装目录下打开MaintenanerceTool.exe 手动添加储存库,要定位一个储存有QT在线安装镜像的网址: https://download.qt.io/online/qtsdkrepo ...
- oracle 启动三步骤
oracle 启动三步骤 oracle启动会经过三个过程,分别是nomount.mount.open 一.nomount 阶段 nomount 阶段,可以看到实例已经启动.oracle进程会根据参数文 ...
- 前端工具mock的使用 - 造数据模拟网络请求
前后端同步开发过程中,有时候前端页面完成了,需要等待后端接口完成部署后才能联调. 这个时候如果不想等待,想自己造数据模拟网络请求,这种情况就能用到mock工具了. mock工具可以用在web网站,也能 ...
- nltk 词性解析
转载链接: https://blog.csdn.net/pengjian444/article/details/81143983
- 区块链基础认识-BTC
1.什么是区块链 a.定义: 从本质上来说区块链就是一种通过将用户的某种特定信息(比如交易信息),通过很多台计算机记录保存并同步的过程,每个区块都记录了对应的交易信息,将这些交易信息串联起来就形成了所 ...
- datatable中的copy和clone的用法区分
dt.copy();//复制结构和数据 dt.clone();//仅复制结构,不复制数据