接口授权常见处理方案之token


服务提供方和调用方同时用某个算法计算出一个token,比较时间来确定token是否有效。

 1 import org.springframework.util.Assert;
 2 
 3 import javax.crypto.Mac;
 4 import javax.crypto.SecretKey;
 5 import javax.crypto.spec.SecretKeySpec;
 6 import java.util.Base64;
 7 import java.util.Date;
 8 
 9 /**
10  * @Author: pengbenlei
11  * @Date: 2020/8/27 11:24
12  * @Description: 接口授权码工具类
13  */
14 public class RequestApiAuthUtil {
15 
16     static final Base64.Encoder encoder = Base64.getEncoder();
17 
18     /**
19      * 请求授权码加密算法
20      *
21      * @param applicationCode  应用唯一码
22      * @param applicationKey 应用私钥
23      * @param timestamp      时间戳
24      */
25     public static String ecode(String applicationCode, String applicationKey, Long timestamp) {
26         String authCode = "";
27         try {
28             authCode = encoder.encodeToString(HmacSHA1Encrypt(applicationCode, applicationKey + timestamp.toString()));
29         } catch (Exception e) {
30             e.printStackTrace();
31         }
32         return authCode;
33     }
34 
35     /**
36      * 请求授权码验证
37      */
38     public static Boolean authCodeVerification(String authCode, String applicationCode, String applicationKey, Long startTime) {
39         Long nowTime = new Date().getTime() / 1000;
40         long timeDifference = nowTime - startTime;
41         // 时间点相差的秒数
42         // 7200秒内视为有效
43         System.out.println("nowTime:" + nowTime + "  startTime:" + startTime + "  timeDifference" + timeDifference);
44         Assert.isTrue(!(timeDifference > 7200 || timeDifference < 0), "Error passing in timestamp");
45         //验证授权码
46         String correctCode = ecode(applicationCode, applicationKey, startTime);
47         Assert.isTrue(correctCode.equals(authCode), "Authorization code error, please check the algorithm or timestamp!");
48         return true;
49     }
50 
51 
52     private static final String MAC_NAME = "HmacSHA1";
53     private static final String ENCODING = "UTF-8";
54 
55     public static byte[] HmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception {
56         byte[] data = encryptKey.getBytes(ENCODING);
57         // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
58         SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
59         // 生成一个指定 Mac 算法 的 Mac 对象
60         Mac mac = Mac.getInstance(MAC_NAME);
61         // 用给定密钥初始化 Mac 对象
62         mac.init(secretKey);
63 
64         byte[] text = encryptText.getBytes(ENCODING);
65         // 完成 Mac 操作
66         return mac.doFinal(text);
67     }
68 }
密钥生成验证工具类
 1 import com.leenleda.common.config.LenledaConfig;
 2 import com.leenleda.common.utils.RedisUtil;
 3 import com.leenleda.wechat.utils.RequestApiAuthUtil;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.stereotype.Component;
 6 import org.springframework.util.Assert;
 7 import org.springframework.web.servlet.HandlerInterceptor;
 8 
 9 import javax.annotation.Resource;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 
13 /**
14  * @Author: pengbenlei
15  * @Date: 2020/8/27 15:02
16  * @Description:
17  */
18 @Component
19 public class ApiAuthInterceptor implements HandlerInterceptor {
20 
21 
22     final
23     RedisUtil redisUtil;
24 
25     public ApiAuthInterceptor(RedisUtil redisUtil) {
26         this.redisUtil = redisUtil;
27     }
28 
29 
30     @Override
31     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
32         // 验证token
33         String token = request.getHeader("token");
34         Assert.notNull(token, "token can not be empty!");
35         // 验证时间戳
36         Long timestamp = Long.valueOf(request.getHeader("timestamp"));
37         Assert.notNull(timestamp, "timestamp can not be empty!");
38         // 验证公钥
39         String publicKey = request.getHeader("public_key");
40         Assert.notNull(publicKey, "applicationCode  can not be empty!");
41         // 验证token有效性
42         RequestApiAuthUtil.authCodeVerification(token, publicKey, privateKey(), timestamp);
43         return true;
44     }
45 
46 }
拦截器验证请求