如何使用Spring Boot实现接口时间戳鉴权
作者:weixin_43833540
这篇文章主要为大家详细介绍了如何使用Spring Boot实现接口时间戳鉴权,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴要了解下
Spring Boot实现接口时间戳鉴权,签名(sign
)和时间戳(ts
)放入请求头(Header)。
一、请求头参数设计
参数名 | 类型 | 说明 |
---|---|---|
ts | Long | 13位时间戳(Unix毫秒值),必填,标识请求有效期 |
sign | String | 签名值,必填,用于校验请求合法性 |
二、签名算法调整(Header版)
1. 构造原始字符串
str = key + url_encode(path) + ts
path:请求的URL路径部分(不含查询参数和域名),例如:/api/v1/user。
url_encode(path):需对路径中的特殊字符进行URL编码(如中文、/等无需编码,但空格需转义为%20)。
2. 生成签名 SIGN
sgin = md5(S).toLowerCase()
结果转换为小写字符串,与请求头中的sign对比校验。
三、Spring Boot实现流程
1. 创建拦截器(Interceptor)
用于拦截请求,校验ts和sign的合法性。
import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Objects; public class AuthInterceptor implements HandlerInterceptor { private final String secretKey; // 从配置文件获取密钥,例如application.properties private final long maxClockSkew = 60 * 1000; // 时间窗口:60秒(允许客户端与服务端的时间误差) public AuthInterceptor(String secretKey) { this.secretKey = secretKey; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 1. 校验时间戳是否存在 String ts = request.getHeader("ts"); if (StringUtils.isEmpty(ts)) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("application/json"); // 返回错误信息:缺少时间戳 return false; } // 2. 校验时间戳格式及有效性 long ts; try { ts = Long.parseLong(ts ); } catch (NumberFormatException e) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 返回错误信息:时间戳格式错误 return false; } long currentTime = System.currentTimeMillis(); if (currentTime - ts > maxClockSkew|| ts - currentTime > maxClockSkew) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回错误信息:请求已过期 return false; } // 3. 校验签名是否存在 String sign= request.getHeader("sign"); if (StringUtils.isEmpty(sign)) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 返回错误信息:缺少签名 return false; } // 4. 构造原始签名字符串并生成签名 String path = request.getRequestURI(); // 获取路径,例如"/api/v1/user" String encodedPath = URLEncoder.encode(path, StandardCharsets.UTF_8.toString()) .replace("+", "%20") // 处理空格编码差异(URLEncoder默认用+,此处统一为%20) .replace("%7E", "~"); // 保留波浪线~的原始格式 String rawString = secretKey + encodedPath + tsHeader; try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(rawString.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); // 转换为小写16进制字符串 } String generatedSign = sb.toString(); // 5. 对比签名 if (!generatedSign.equals(sign)) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回错误信息:签名校验失败 return false; } } catch (Exception e) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return false; } return true; // 校验通过,允许请求继续 } }
2. 配置拦截器(WebMvcConfigurer)
将拦截器注册到Spring Boot的拦截器链中,指定需要鉴权的接口路径。
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { private final String secretKey; // 从配置文件获取密钥,例如通过@Value注入 public WebConfig(String secretKey) { this.secretKey = secretKey; } @Override public void addInterceptors(InterceptorRegistry registry) { AuthInterceptor authInterceptor = new AuthInterceptor(secretKey); registry.addInterceptor(authInterceptor) .addPathPatterns("/api/v1/**") // 需要鉴权的接口路径(如/api/v1下所有接口) .excludePathPatterns("/api/v1/public/**"); // 无需鉴权的公共接口(可选) } }
3. 配置文件(application.properties)
# 密钥(建议从环境变量或配置中心获取,而非硬编码) auth.secret-key=your_secret_key_here
四、客户端请求示例(以Postman为例)
1. 请求头参数
名称 | 值 |
---|---|
ts | 1686048000000(当前时间戳,13位Long) |
sign | 计算得到的签名值(如e10adc3949ba59abbe56e057f20f883e) |
2. 签名计算步骤(JavaScript示例)
function generateSignature(key, path, ts) { const encodedPath = encodeURIComponent(path).replace(/[!'()*]/g, encodeURIComponent); // 严格编码特殊字符 const rawString = key + encodedPath + ts; const md5 = require('crypto-js/md5'); // 需要安装crypto-js库 return md5(rawString).toString().toLowerCase(); } // 示例调用 const key = 'your_secret_key'; const path = '/api/v1/user'; // 接口路径 const ts = Date.now(); // 当前时间戳(13位) const sign = generateSignature(key, path, ts); console.log(sign); // 输出签名值
到此这篇关于如何使用Spring Boot实现接口时间戳鉴权的文章就介绍到这了,更多相关Spring Boot接口时间戳鉴权内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!