Java接口签名
# Java接口签名
# 概述
当我们需要针对当前的系统开发一个对外开放的接口时,那么调用者必然没有我们的Token,就需要对调用者进行签名验证
签名验证采用主流的验证方式,采用Java接口签名(Signature)
的方式,通过Aspect-Oriented Programming(AOP)进行拦截验证。
# 实施代码
签名相关的配置信息对象
@Data
@Configuration
@ConfigurationProperties(prefix = "pool")
public class SecretConfig {
private Boolean enable = false;
private Long expirationTime = 8L;
private List<Secret> secretList = null;
@Data
public static class Secret {
private String appKey;
private String appSecret;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
权限认证
@Slf4j
@Aspect
@Component
public class AccessTokenAspect {
/**
* 获取签名相关的配置信息
*/
@Autowired
private SecretConfig secretConfig;
/**
* 定义了一个切入点表达式
* 拦截要进行签名认证的方法或类
*/
@Pointcut("execution(* *(..))")
public void before() {
}
/**
* 满足上述切入点表达式的情况下,会执行doAround(JoinPoint point)方法。
* @param point JoinPoint类型的参数,表示被拦截的方法的相关信息
*/
@Before("before()")
public Object doAround(JoinPoint point) {
// 获取当前请求的上下文信息,然后从中提取出HttpServletRequest对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
return checkSignature(request);
}
/**
* 进行验证签名
* @param request 请求对象
*/
public boolean checkSignature(HttpServletRequest request) {
// 通过配置信息 验证是否进行签名认证
if (!secretConfig.getEnable()) {
throw new LogicException("签名验证失败");
}
// 获取参数对象
Map<String, String> paramMap = new HashMap<>();
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
for (String paramValue : paramValues) {
paramMap.put(paramName, paramValue);
}
}
// 获取接口签名 时间戳 请求随机串 appKey
String signature = request.getHeader("signature");
String timestamp = request.getHeader("timestamp");
String noncestr = request.getHeader("noncestr");
String appKey = request.getHeader("appKey");
// 验证签名时间是否过期
checkValidity(timestamp);
// 获取对应的Secret配置
List<SecretConfig.Secret> secretList = secretConfig.getSecretList()
.stream().filter(p -> p.getAppKey().equals(appKey)).collect(Collectors.toList());
// 无效的appKey
if (CollectionUtil.isEmpty(secretList)) {
throw new LogicException("签名验证失败 无效的appKey");
}
// 根据请求参数和获取的配置项生成签名
Map<String, Object> parms = new TreeMap<>();
parms.put("appKey", appKey);
parms.put("timestamp", timestamp);
parms.put("noncestr", noncestr);
PoolSecretConfig.Secret secretConfig = secretList.get(0);
String encrypted = buildSignature(paramMap, parms, secretConfig);
//签名比对
if (encrypted.equals(signature)) {
return true;
}
throw new LogicException("签名验证失败");
}
private String buildSignature(Map<String, String> paramMap, Map<String, Object> maps, PoolSecretConfig.Secret secretConfig) {
try {
StringBuffer stringBuffer = new StringBuffer();
if (!paramMap.isEmpty()) {
stringBuffer.append(paramMap);
}
//添加appSecret
stringBuffer.append(secretConfig.getAppKey())
.append(maps.get("timestamp"))
.append(maps.get("noncestr"))
.append(secretConfig.getAppSecret());
return DigestUtils.md5DigestAsHex(stringBuffer.toString().getBytes()).toUpperCase();
} catch (Exception e) {
throw new LogicException("签名转换异常");
}
}
/**
* 验证时间是否过期
* @param timestamp 请求时间
*/
public void checkValidity(String timestamp) {
try {
// 获取当前时间
DateTime date = DateUtil.date(System.currentTimeMillis());
// 转换签名中的时间戳
DateTime timestampTime = DateUtil.date(Long.parseLong(timestamp));
// 验证签名是否过期
long between = DateUtil.between(date, timestampTime, DateUnit.HOUR);
if (secretConfig.getExpirationTime() < between) {
throw new LogicException("签名验证失败 签名已失效");
}
} catch (Exception e) {
throw new LogicException("签名验证失败 签名格式错误");
}
}
}
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
122
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
122
上次更新: 2023/11/01, 15:16:13