Http参数验签(基于AOP)

实现

要实现参数验签, 首先需要提取出请求参数, 这里无论 GET 还是 POST 请求, 我们都将参数提取出来放在map中处理

提取参数并排序

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
package cn.idea360.demo.modules.sign;

import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
* @author 当我遇上你
* @公众号 当我遇上你
* @since 2020-08-30
*/
public class RequestUtils {


/**
* 将URL请求参数转换成Map
* @author show
* @param request
*/
public static Map<String, String> getUrlParams(HttpServletRequest request) {

String param = "";
try {
param = URLDecoder.decode(request.getQueryString(), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Map<String, String> result = new HashMap<>(16);
String[] params = param.split("&");
for (String s : params) {
int index = s.indexOf("=");
result.put(s.substring(0, index), s.substring(index + 1));
}
return result;
}

/**
* 获取body中参数
* @param request
* @return
* @throws IOException
*/
public static Map<String, String> getBodyParams (HttpServletRequest request) throws IOException {
String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
//转化成json对象
return JSONObject.parseObject(body, Map.class);
}


/**
* 获取url参数和body参数
* @param request
* @return
* @throws IOException
*/
public static SortedMap<String, String> getAllParams(HttpServletRequest request) throws IOException {

SortedMap<String, String> sortedParams = new TreeMap<>();

// 获取url参数
Map<String, String> urlParams = getUrlParams(request);
for (Map.Entry entry : urlParams.entrySet()) {
sortedParams.put((String) entry.getKey(), (String) entry.getValue());
}

// 获取body参数
if (!HttpMethod.GET.name().equals(request.getMethod())) {
Map<String, String> bodyParams = getBodyParams(request);
if (null != bodyParams) {
for (Map.Entry entry : bodyParams.entrySet()) {
sortedParams.put((String) entry.getKey(), (String) entry.getValue());
}
}
}
return sortedParams;
}
}

参数验签

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
package cn.idea360.demo.modules.sign;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.DigestUtils;

import java.util.*;

/**
* @author 当我遇上你
* @公众号 当我遇上你
* @since 2020-08-30
*/
@Slf4j
public class SignUtils {


/**
* 获取参数签名
* @param params
* @return
*/
public static String getParamsSign(SortedMap<String, String> params) {

//要先去掉 Url 里的 Sign
params.remove("sign");
// 这里把map转换为了json对象字符串,当然也可以取出value拼接或者其他方式组成的String
String paramsJsonStr = JSONObject.toJSONString(params);

String md5 = DigestUtils.md5DigestAsHex(paramsJsonStr.getBytes()).toUpperCase();
log.info("加签参数: {}, md5摘要: {}", paramsJsonStr, md5);

return md5;
}

/**
* 参数验签
* @param params 已排序参数
* @return 验证签名结果
*/
public static boolean verifySign(SortedMap<String, String> params) {

String urlSign = params.get("sign");
log.info("Url Sign : {}", urlSign);

if (StringUtils.isBlank(urlSign)) {
return false;
}

//把参数加密
String paramsSign = getParamsSign(params);
log.info("Param Sign : {}", paramsSign);

return StringUtils.isNotBlank(paramsSign) && urlSign.equals(paramsSign);
}
}

AOP实现

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
/**
* 接口验签
*/

@Slf4j
@Aspect
@Component
public class SignAspect {

@Pointcut("@annotation(com.idea360.auth.common.annotation.Sign)")
public void signPointCut() {
}

@Before("signPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {

// 获取方法请求参数
Object[] args = joinPoint.getArgs();
// 参数名
String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();

Map<String, String> unSortedMap = new HashMap<>();
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse) {
continue;
}
String json = GsonUtils.toJson(args[i]);
if (GsonUtils.isJSON(json)) {
Map<String, String> map = GsonUtils.fromJson(json, Map.class);
unSortedMap.putAll(map);
} else {
unSortedMap.put(argNames[i], String.valueOf(args[i]));
}
}
// 自然排序
SortedMap<String, String> sortedMap = new TreeMap<>(unSortedMap);
log.info("参数验签, request params: [{}]", sortedMap.toString());

if (!SignUtils.verifySign(sortedMap)) {
throw new RuntimeException("非法请求");
}
}
}
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
public class GsonUtils {

private static final Gson gson = new Gson();

/**
* 判断是否json格式
* @param jsonStr
* @return
*/
public static boolean isJSON(String jsonStr) {
JsonElement jsonElement;
try {
jsonElement = JsonParser.parseString(jsonStr);
} catch (Exception e) {
return false;
}
if (jsonElement == null) {
return false;
}
if (!jsonElement.isJsonObject()) {
return false;
}
return true;
}

/**
* 判断是否json对象
* @param o
* @return
*/
public static boolean isJSONObject(Object o) {
try {
String json = gson.toJson(o);
return isJSON(json);
} catch(com.google.gson.JsonSyntaxException ex) {
return false;
}
}


public static String toJson(Object o) {
return gson.toJson(o);
}

public static <T> T fromJson(String json, Class<T> clz) {
return gson.fromJson(json, clz);
}
}

最后

本文到此结束,感谢阅读。如果您觉得不错,请关注公众号【当我遇上你】,您的支持是我写作的最大动力。