java防止接口被篡改--接口签名(简单版本)续
一、前言
- 此次来说一下另一种简单粗暴的签名方案。相对于之前的签名方案,对body、paramenter、path variable的获取都做了简化的处理。也就是说这种方式针所有数据进行了签名,并不能指定某些数据进行签名。
二、签名规则
1、线下分配appid和appsecret,针对不同的调用方分配不同的appid和appsecret
2、加入timestamp(时间戳),10分钟内数据有效
3、加入流水号nonce(防止重复提交),至少为10位。针对查询接口,流水号只用于日志落地,便于后期日志核查。 针对办理类接口需校验流水号在有效期内的唯一性,以避免重复请求。
4、加入signature,所有数据的签名信息。
以上红色字段放在请求头中。
三、签名的生成
signature字段生成规则如下。
1、数据部分
- Path Variable:按照path中的字典顺序将所有value进行拼接
- Parameter:按照key=values(多个value按照字典顺序拼接)字典顺序进行拼接
- Body:从request inputstream中获取保存为String形式
- 如果存在多种数据形式,则按照body、parameter、path variable的顺序进行再拼接,得到所有数据的拼接值。
上述拼接的值记作 Y。
2、请求头部分
- X=”appid=xxxnonce=xxxtimestamp=xxx”
3、生成签名
- 最终拼接值=XY
- 最后将最终拼接值按照如下方法进行加密得到签名。
- signature=org.apache.commons.codec.digest.HmacUtils.AesEncodeUtil(app secret, 拼接的值);
四、签名算法实现
- 注:省去了X=”appid=xxxnonce=xxxtimestamp=xxx”这部分。
1、自定义Request对象
为什么要自定义request对象,因为我们要获取request inputstream(默认只能获取一次)
1 | public class BufferedHttpServletRequest extends HttpServletRequestWrapper { |
替换默认的request对象
1 | @Configuration |
1 | public class RequestCachingFilter extends OncePerRequestFilter { |
2、签名切面
1 | @Aspect |
1 | public class SignUtil { |
五、签名验证
- 简单写了一个包含body参数,parameter参数,path variable参数的controller
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@RestController
@RequestMapping("example")
public class ExampleController {
@PostMapping(value = "test/{var1}/{var2}", produces = MediaType.ALL_VALUE)
public String myController(@PathVariable String var1
, @PathVariable String var2
, @RequestParam String var3
, @RequestParam String var4
, @RequestBody User user) {
return String.join(",", var1, var2, var3, var4, user.toString());
}
private static class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("name", name)
.append("age", age)
.toString();
}
}
} - 通过 签名核心工具类SignUtil 的main方法生成一个签名,通过如下命令验证
1 | curl -X POST \ |