SpringBoot 接口签名
核心原理
通过秘钥(不公开)对数据(请求数据)进行加密(加密算法公开),加密过程不可逆,所以只有拥有秘钥的双方才能对数据进行正确的加密,从而确保请求是由可信来源发出的,并且请求在传输过程中没有被篡改。
注:
- 接口签名其实还能用作防止请求参数不被篡改
- 一般appId和appSecret成对出现,因为可能秘钥有多个,此时就需要根据appId从数据库中查询appSecret
签名算法
- 生成签名的方法通常将请求参数按照特定规则计算出一个签名值;
- 验证签名的方法则是对接收到的请求参数进行同样的处理,并计算出一个签名值,然后与请求中携带的签名值进行比对;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Signature {
/**
* 获取签名
* @param secretKey 密钥
* @param data 需要签名的数据
* @return 签名
*/
public static String signWithHmacSha1(String secretKey, String data) {
try {
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8")));
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 验证签名
* @param secretKey 密钥
* @param data 需要签名的数据
* @param hmac 已经签名的数据
* @return true:签名一致
*/
public static boolean verify(String secretKey, String data, String hmac) {
String calculatedHmac = signWithHmacSha1(secretKey, data);
return calculatedHmac.equals(hmac);
}
}
请求拦截器
一般来说接口做了签名其实基本已经ok了,但为了更强的安全性,例如防止DDOS攻击、全局校验处理等,通常业界会将签名校验集成在拦截器中,与业务代码分离
注:如果项目中使用了认证授权框架,例如springsecurity,仍需要放行接口,不然请求会被拦截导致无法到底自定义的拦截器;(当然此处也可以改为自定义过滤器,加入springsecurity框架的过滤器链中)
自定义拦截器
import com.xz.bd.business.utils.SignatureUtil;
import com.xz.bd.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Component
public class SignInterceptor implements HandlerInterceptor {
// 此处需要使用注入bean的形式,才能获取到配置文件中的数据
@Value("${secretKey}")
private String secret;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/**
* 对签名请求进行验证
*/
String sign = request.getHeader("sign");
String dateTime = request.getHeader("dateTime");
if(System.currentTimeMillis()-Long.parseLong(dateTime) > 1000*30){
log.error("数据大屏:请求签名已过期");
return false;
}
if (sign == null || dateTime == null) {
log.error("数据大屏:请求签名为空");
return false;
}
if (SignatureUtil.verify(secret, dateTime, sign)) {
return true;
} else {
log.error("数据大屏:请求签名验证失败");
return false;
}
}
}
拦截器注册
import com.xz.bd.business.interceptor.SignInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class SignInterceptorConfig extends WebMvcConfigurerAdapter {
@Autowired
private SignInterceptor signInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注入拦截器,并声明该拦截器对哪些请求生效
registry.addInterceptor(signInterceptor).addPathPatterns("/dataScreen/**");
}
}
参考链接
【1】https://blog.csdn.net/u011974797/article/details/138123261
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2020-12-24 Python数据分析(jupyter notebook上实现)