X-Ca-Key / X-Ca-Secret 鉴权方式,这个通常出现在 API 网关、开放平台(比如阿里云 API 网关) 的接口调用鉴权场景。
Java 后端实现大体思路和签名机制类似于 API Key + Secret 签名校验。
1. 鉴权机制原理
-
客户端(调用方):
-
拿到
X-Ca-Key(类似 appKey,标识调用方身份) -
拿到
X-Ca-Secret(类似 appSecret,调用方私钥,不可泄露) -
按照 约定的签名算法(通常是 HMAC-SHA256)对请求参数/头部/路径进行签名
-
在请求头中放入:
X-Ca-Key: {appKey} X-Ca-Signature: {签名结果}
-
-
服务端(被调用方):
- 根据
X-Ca-Key查出对应的X-Ca-Secret - 使用相同的签名算法,对请求内容进行签名
- 对比客户端传来的
X-Ca-Signature,一致则通过,反之拒绝
- 根据
2. 签名的一般规则
不同平台可能略有差异,但常见规则:
-
签名字符串组成:
- HTTP 方法(
GET/POST) - 请求路径
- 排序后的请求参数(query/body)
- 特定头部(如
X-Ca-Key)
- HTTP 方法(
-
签名算法:HMAC-SHA256 / SHA1,使用
X-Ca-Secret作为密钥 -
Base64 编码:通常签名结果会再做一次
Base64.encode
3. Java 后端校验实现(示例)
3.1 签名工具类
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class SignUtil {
public static String sign(String data, String secret) {
try {
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmacSha256.init(secretKey);
byte[] hash = hmacSha256.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash); // 常见是 Base64
} catch (Exception e) {
throw new RuntimeException("签名失败", e);
}
}
}
3.2 后端鉴权过滤器
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
@Component
public class ApiAuthInterceptor implements HandlerInterceptor {
// 模拟存储 appKey 和 appSecret,可以用数据库/Redis
private static final Map<String, String> APP_KEYS = new HashMap<>();
static {
APP_KEYS.put("testKey", "testSecret");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String appKey = request.getHeader("X-Ca-Key");
String signature = request.getHeader("X-Ca-Signature");
if (appKey == null || signature == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "缺少鉴权头");
return false;
}
String secret = APP_KEYS.get(appKey);
if (secret == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效的Key");
return false;
}
// 拼接待签名字符串(示例:HTTP方法 + 路径 + 排序参数)
String method = request.getMethod();
String path = request.getRequestURI();
// 获取参数并排序
Map<String, String[]> params = request.getParameterMap();
StringBuilder sb = new StringBuilder();
params.keySet().stream().sorted().forEach(k -> sb.append(k).append("=").append(params.get(k)[0]).append("&"));
if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1);
String signData = method + "\n" + path + "\n" + sb;
// 计算签名
String serverSign = SignUtil.sign(signData, secret);
if (!serverSign.equals(signature)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "签名不匹配");
return false;
}
return true;
}
}
3.3 Spring Boot 注册拦截器
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.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ApiAuthInterceptor apiAuthInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(apiAuthInterceptor).addPathPatterns("/api/**");
}
}
4. 调用方请求示例
客户端调用时需要:
GET /api/orders?orderId=1001
X-Ca-Key: testKey
X-Ca-Signature: AabCkL123xyz==
签名字符串规则由服务端和客户端保持一致,否则鉴权失败。
5. 总结
- X-Ca-Key = 公钥,用来标识调用方
- X-Ca-Secret = 私钥,用来生成签名,不可泄露
- 鉴权流程 = 客户端签名 → 服务端验证签名
- 好处:避免伪造请求、防止参数被篡改,常用于 API 开放平台、网关接口保护
5362

被折叠的 条评论
为什么被折叠?



