本文目录导读:

我来详细介绍Java中实现接口签名的几种常见方法。
什么是接口签名
接口签名是通过对请求参数进行加密处理,生成一段校验码,用于验证请求的合法性和完整性,防止数据被篡改。
基本实现思路
// 签名生成流程 1. 收集所有请求参数 2. 按参数名排序 3. 拼接成字符串 4. 加上密钥 5. 进行加密(MD5/SHA等) 6. 生成签名
完整实现示例
1 工具类实现
import java.security.MessageDigest;
import java.util.*;
public class SignUtil {
/**
* 生成签名
* @param params 请求参数Map
* @param secret 密钥
* @return 签名串
*/
public static String generateSign(Map<String, String> params, String secret) {
// 1. 移除签名本身(防止重复计算)
params.remove("sign");
// 2. 获取所有参数名并排序
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
// 3. 拼接参数
StringBuilder sb = new StringBuilder();
for (String key : keys) {
String value = params.get(key);
if (value != null && !value.isEmpty()) {
sb.append(key).append("=").append(value).append("&");
}
}
// 4. 添加密钥
sb.append("key=").append(secret);
// 5. MD5加密
return md5(sb.toString()).toUpperCase();
}
/**
* 验证签名
* @param params 请求参数
* @param secret 密钥
* @return 是否验证通过
*/
public static boolean verifySign(Map<String, String> params, String secret) {
String sign = params.get("sign");
if (sign == null || sign.isEmpty()) {
return false;
}
String calSign = generateSign(params, secret);
return calSign.equals(sign);
}
/**
* MD5加密
*/
private static String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("MD5加密失败", e);
}
}
}
2 使用示例
public class SignDemo {
public static void main(String[] args) {
// 1. 请求参数
Map<String, String> params = new HashMap<>();
params.put("appId", "10001");
params.put("timestamp", "1695102400");
params.put("nonce", "random123");
params.put("data", "{\"name\":\"张三\",\"age\":25}");
// 2. 密钥(实际应用中应该从配置文件或密钥服务器获取)
String secret = "your-secret-key-123456";
// 3. 生成签名
String sign = SignUtil.generateSign(params, secret);
params.put("sign", sign);
System.out.println("签名结果: " + sign);
// 4. 验证签名
boolean isValid = SignUtil.verifySign(params, secret);
System.out.println("签名验证: " + (isValid ? "通过" : "失败"));
}
}
Spring Boot集成实现
1 自定义注解
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VerifySign {
// 是否需要验证签名
boolean required() default true;
}
2 拦截器实现
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
public class SignInterceptor implements HandlerInterceptor {
private final String secret;
public SignInterceptor(String secret) {
this.secret = secret;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 获取请求参数
Map<String, String> params = getParams(request);
// 验证签名
if (!SignUtil.verifySign(params, secret)) {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":401,\"msg\":\"签名验证失败\"}");
return false;
}
return true;
}
private Map<String, String> getParams(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Enumeration<String> names = request.getParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
params.put(name, request.getParameter(name));
}
return params;
}
}
3 配置拦截器
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 {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SignInterceptor("your-secret-key"))
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**");
}
}
Controller层使用
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class UserController {
@PostMapping("/user/create")
@VerifySign
public Result createUser(@RequestParam Map<String, String> params) {
// 业务逻辑
return Result.success();
}
}
增强功能实现
1 防重放攻击
public class AdvancedSignUtil extends SignUtil {
private static final long TIMEOUT = 5 * 60 * 1000; // 5分钟超时
public static boolean verifySignWithNonce(Map<String, String> params, String secret) {
// 1. 验证签名
if (!verifySign(params, secret)) {
return false;
}
// 2. 验证时间戳
String timestamp = params.get("timestamp");
if (timestamp == null) {
return false;
}
long time = Long.parseLong(timestamp);
if (Math.abs(System.currentTimeMillis() - time * 1000) > TIMEOUT) {
return false; // 请求超时
}
// 3. 验证nonce(防止重放)
String nonce = params.get("nonce");
if (nonce == null || isNonceUsed(nonce)) {
return false;
}
saveNonce(nonce);
return true;
}
// 实际应用中应该使用Redis存储
private static Set<String> usedNonces = new HashSet<>();
private static boolean isNonceUsed(String nonce) {
return usedNonces.contains(nonce);
}
private static void saveNonce(String nonce) {
usedNonces.add(nonce);
}
}
2 客户端示例
public class ApiClient {
private String appId;
private String secret;
public ApiClient(String appId, String secret) {
this.appId = appId;
this.secret = secret;
}
public Map<String, String> buildRequest(Map<String, String> data) {
Map<String, String> params = new HashMap<>();
params.put("appId", appId);
params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
params.put("nonce", UUID.randomUUID().toString().replace("-", ""));
params.put("data", JSON.toJSONString(data));
// 生成签名
String sign = SignUtil.generateSign(params, secret);
params.put("sign", sign);
return params;
}
}
最佳实践建议
- 使用HTTPS:确保传输层安全
- 密钥管理:密钥不要硬编码,使用配置中心
- 时间戳验证:防止重放攻击
- 参数排序:保证签名一致性
- 包含敏感数据:签名应包含所有参数
- 错误处理:提供清晰的错误信息
这就是Java接口签名的完整实现方案,可以根据实际需求选择合适的实现方式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播