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 ...
随机推荐
- vscode中vue代码颜色插件
vue提示插件[Vscode] 编者寄语:vscode的确是前端开发中很好的工具,安装颜色插件,从视觉上是美的享受.曾经的我遇到了vscode代码全是灰色,黑色的困惑,后来整理找到方法,整 ...
- Thymleaf 从某处(不包含某处)开始截取字符串到末尾
简单描述:数据库存放的是id+name,但是做展示的时候,只需要展示name,不展示id.不管是在前台还是在后台,使用传统的方法截取,也是可以的,但是thymleaf提供了一种截取字符串,可以实现从某 ...
- IDEA启动maven项目
一.安装IDEA 自行到官网下载,有条件请购买版权 地址:https://www.jetbrains.com/idea/ 二.修改快捷键(如果不是eclipse老用户请忽略这段) 左上角File→Sr ...
- log4j配置,输出sql到控制台
网上的 # Global logging configuration log4j.rootLogger=ERROR, stdout # log4j.logger后面跟着的是项目dao包路径,里面全部都 ...
- Redis实战 - 3.Hash
hash Redis的Hash有点像一个对象(object),一个Hash里面可以存多个Key-Value对作为它的field,所以它通常可以用来表示对象. Hash里面能存放的值也能作为String ...
- PHP金钱数字转金钱大写
/* * 数字金额转换成中文大写金额的函数 * String Int $num 要转换的小写数字或小写字符串 * return 大写数字 */ function num_to_rmb($num){ $ ...
- 为什么Kafka速度那么快
Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间,但是实际上,Kafka的特性之一就是高吞吐率. 即使是普通的服务器,Kafka也可以轻松支持每秒 ...
- 将最小的OWIN身份验证添加到现有的ASP.NET MVC应用程序
https://weblog.west-wind.com/posts/2015/Apr/29/Adding-minimal-OWIN-Identity-Authentication-to-an-Exi ...
- Android进阶:一、日志打印和保存策略
前言: 项目开始没有做好日志统计工作,每次有问题后端都得找前端对接,严重影响工作效率.最近特地在项目中加上日志保存策略,在此分享,供需要的人学习. 一.更详细的日志信息 既然决定自定义一个log,那我 ...
- HTML5+CSS3 1
html5标准模板 <!DOCTYPE html> //<!DOCTYPE>标签 向浏览器声明当前文档使用的HTML版本,<!DOCTYPE html>适用于所 ...