现有A系统,B系统,A系统启动的时候调用B系统的注册接口API1(把A系统配置信息注册到B系统),A系统定时向B系统接口AP2发送心跳信息,B系统根据业务情况,调用A系统的业务接口AP3,请设计两系统的接口认证方式。
以下是为A系统(Python)与B系统(Spring Boot)设计的双向安全认证方案及关键代码实现,结合JWT、数字签名和HTTPS加密,确保注册、心跳、业务调用的安全可靠。
接口 | 认证方式 | 安全机制 | 密钥管理 |
---|---|---|---|
API1(注册) | 预共享密钥 + HTTPS | HMAC签名 + TLS加密 | 预置静态密钥 |
API2(心跳) | JWT + 时间戳签名 | 动态Token + 防重放 | 定期刷新Token |
AP3(业务调用) | 双向JWT + 请求签名 | 非对称加密 + Nonce校验 | 公钥证书交换 |
流程:A系统启动时,使用预共享密钥生成HMAC签名,B系统验证后返回长期凭证。
安全机制:
Python (A系统) 关键代码:
import requests
import hmac
import hashlib
def register_to_b():
url = "https://b-system/api1"
shared_secret = "pre-shared-key"
config = {"system_id": "A", "public_key": "A_PUBLIC_KEY"}
# 生成HMAC签名
signature = hmac.new(
shared_secret.encode(),
json.dumps(config).encode(),
hashlib.sha256
).hexdigest()
headers = {"X-Signature": signature}
response = requests.post(url, json=config, headers=headers, verify=True) # 启用HTTPS验证
return response.json() # 返回{"access_token": "xxx", "refresh_token": "yyy"}
Spring Boot (B系统) 关键代码:
@RestController
public class RegistrationController {
@PostMapping("/api1")
public ResponseEntity> register(@RequestBody Map body,
@RequestHeader("X-Signature") String signature) {
// 1. 验证HMAC签名
String computedSig = HmacUtils.hmacSha256Hex("pre-shared-key", body.toString());
if (!computedSig.equals(signature)) {
return ResponseEntity.status(401).body("Invalid signature");
}
// 2. 生成长期Token并存储公钥
String accessToken = Jwts.builder().setSubject(body.get("system_id")).compact();
redis.savePublicKey(body.get("system_id"), body.get("public_key")); // 存储公钥
return ResponseEntity.ok(Map.of("access_token", accessToken));
}
}
流程:A系统使用JWT和当前时间戳签名,B系统验证Token有效性和时间戳防重放。
安全机制:
Python (A系统) 关键代码:
import jwt
import time
def send_heartbeat():
token = "A_ACCESS_TOKEN" # 注册时获取
private_key = "A_PRIVATE_KEY"
timestamp = int(time.time())
# 用私钥签名时间戳+Token
signature = jwt.encode({"token": token, "ts": timestamp}, private_key, algorithm="RS256")
# 发送请求
response = requests.post(
"https://b-system/api2",
headers={"Authorization": f"Bearer {token}", "X-Signature": signature}
)
if response.status_code == 401: # Token过期则刷新
refresh_token()
Spring Boot (B系统) 关键代码:
@PostMapping("/api2")
public ResponseEntity> heartbeat(@RequestHeader("Authorization") String authHeader,
@RequestHeader("X-Signature") String signature) {
// 1. 提取JWT并验证
String token = authHeader.replace("Bearer ", "");
if (!JwtUtils.validateToken(token)) { // 校验JWT有效性
return ResponseEntity.status(401).build();
}
// 2. 验证时间戳签名
String publicKey = redis.getPublicKey("A");
Claims claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(signature).getBody();
long ts = claims.get("ts", Long.class);
if (Math.abs(System.currentTimeMillis()/1000 - ts) > 30) { // 防重放
return ResponseEntity.status(403).body("Timestamp expired");
}
return ResponseEntity.ok().build();
}
流程:B系统用私钥签名请求(含Nonce),A系统用B的公钥验签并校验Nonce。
安全机制:
Spring Boot (B系统) 关键代码:
public void callA() {
String bToken = "B_TO_A_TOKEN"; // A系统注册时颁发
String payload = "{...}";
String nonce = UUID.randomUUID().toString();
long ts = System.currentTimeMillis();
// 用B的私钥生成签名
String signature = Jwts.builder()
.claim("nonce", nonce)
.claim("ts", ts)
.signWith(SignatureAlgorithm.RS256, bPrivateKey)
.compact();
// 调用A系统接口
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + bToken);
headers.add("X-Signature", signature);
new RestTemplate().post("https://a-system/ap3", new HttpEntity<>(payload, headers));
}
Python (A系统) 关键代码:
from flask import Flask, request
import jwt
app = Flask(__name__)
@app.route('/ap3', methods=['POST'])
def handle_business():
token = request.headers.get("Authorization").split()[1]
signature = request.headers.get("X-Signature")
# 1. 验证B系统的Token有效性
if token != "B_TO_A_TOKEN":
return "Invalid token", 401
# 2. 用B的公钥验证签名
try:
claims = jwt.decode(signature, "B_PUBLIC_KEY", algorithms=["RS256"])
if claims["nonce"] in used_nonces: # 校验Nonce是否重复
return "Replay attack", 403
used_nonces.add(claims["nonce"])
except jwt.InvalidSignatureError:
return "Invalid signature", 401
return "Success", 200
cryptography
库)antMatchers("/api2").permitAll().rateLimit(1/min)
场景 | 处理方案 |
---|---|
心跳丢失 | A系统重试3次后触发重新注册 |
Token过期 | A系统用refresh_token 调用B的刷新接口 |
签名失效 | B系统返回401并记录审计日志(ELK收集) |
方案优势:
- 分层认证:注册接口独立保障系统信任,业务接口轻量化
- 零信任设计:每次请求验证签名+时效,避免长期凭证泄露风险
- 跨语言兼容:Python与Spring Boot通过标准JWT和HTTPS交互