http://my.oschina.net/u/2288185/blog/488552
加密方式 AES
spring jar 包 pom.xml配置(注意版本)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
<
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做如下 配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<!-- 启动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方法即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
@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
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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 {
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
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);
}
}
}
|
这样功能就实现了,欢迎大家一期交流。