springboot三方系统接口调用
1.提供方接口
@RestController public class AiAuthService { @Autowired private RedisTemplate<String, String> redisTemplate; // 用于存储已使用的nonce @Value("${ai.secretKey}") // 假设服务器有预设的密钥 private String secretKey; @PostMapping("/auth/token") public ResponseEntity<AiApiResponse<String>> authenticate(@RequestBody AiAuthRequest request) { try { // 1. 检查必需参数 if (request.getClientId() == null || request.getTimestamp() == null || request.getNonce() == null || request.getSign() == null) { return ResponseEntity.ok(AiApiResponse.error("缺少必需参数")); } // 2. 校验clientId是否有效 if (!isValidClientId(request.getClientId())) { return ResponseEntity.ok(AiApiResponse.error("无效的客户端ID")); } // 3. 校验时间戳(防止重放攻击,比如时间戳不能超过5分钟) long currentTime = System.currentTimeMillis(); if (Math.abs(currentTime - request.getTimestamp()) > 5 * 60 * 1000) { // 5分钟 return ResponseEntity.ok(AiApiResponse.error("时间戳过期")); } // 4. 校验nonce是否已使用(防止重放攻击) String nonceKey = "ai_nonce:" + request.getNonce(); if (redisTemplate.hasKey(nonceKey)) { return ResponseEntity.ok(AiApiResponse.error("随机数已使用")); } // 将nonce存入缓存,设置过期时间 redisTemplate.opsForValue().set(nonceKey, "used", 5, TimeUnit.MINUTES); // 5. 校验签名 String expectedSign = SignUtils.md5("clientId=" + request.getClientId() + "&nonce=" + request.getNonce() + "×tamp=" + request.getTimestamp()); if (!expectedSign.equals(request.getSign())) { return ResponseEntity.ok(AiApiResponse.error("签名验证失败")); } // 6. 所有校验通过,生成并返回token或URL String token = generateToken(request.getClientId()); return ResponseEntity.ok(AiApiResponse.success(token)); } catch (Exception e) { return ResponseEntity.ok(AiApiResponse.error("认证失败: " + e.getMessage())); } } private boolean isValidClientId(String clientId) { // 实际实现可能是查询数据库或配置 return "valid_client_id".equals(clientId); // 示例 } private String generateToken(String clientId) { // 实际实现可能生成JWT或其他类型的token return "generated_token_for_" + clientId; } }
2.调用方接口
@Slf4j @Service public class AiAuthRestTemplateService { @Value("${ai.clientId}") private String clientId; @Value("${ai.url}") private String aiUrl; @Value("${ai.webIp}") private String webUrl; @Value("${ai.devIp}") private String devIp; private final RestTemplate restTemplate; public AiAuthRestTemplateService() { this.restTemplate = new RestTemplate(); // 设置SSL忽略 disableSSLValidation(); } public String getAuthToken() { Long timestamp = System.currentTimeMillis(); String nonce = IdWorker.get32UUID().substring(0, 12); // 签名规则 String sign = SignUtils.md5("clientId=" + clientId + "&nonce=" + nonce + "×tamp=" + timestamp); AiAuthRequest request = AiAuthRequest.builder() .clientId(clientId) .timestamp(timestamp) .nonce(nonce) .sign(sign) .build(); log.info("AI智能体URL---:{}", aiUrl); try { ResponseEntity<AiApiResponse<String>> response = restTemplate.exchange( aiUrl, HttpMethod.POST, new HttpEntity<>(request), new ParameterizedTypeReference<AiApiResponse<String>>() { } ); AiApiResponse<String> responseBody = response.getBody(); if (responseBody == null && !"000000".equals(responseBody.getCode())) { return "获取AI智能体数据失败:" + responseBody.getMessage(); } if (responseBody.getData().contains(devIp)) { String webAddres = responseBody.getData().replace(devIp, webUrl); log.info("ai智能体前端访问的URL:{}", webAddres); return webAddres; } return responseBody.getData(); } catch (Exception e) { return "AI智能体调用网络故障---:" + e.getMessage(); } } private void disableSSLValidation() { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, new SecureRandom()); SSLSocketFactory factory = sslContext.getSocketFactory(); HttpsURLConnection.setDefaultSSLSocketFactory(factory); HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); } catch (Exception e) { throw new RuntimeException("禁用SSL验证失败", e); } } }
3.MD5加密工具
import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class SignUtils { /** * 使用JDK自带的MessageDigest实现MD5加密 * * @param data 待加密的数据 * @return MD5加密后的小写十六进制字符串 */ public static String md5(String data) { // 检查字符串 if (data == null || data.isEmpty()) { throw new IllegalArgumentException("SignUtils md5 Input data cannot be null or empty"); } try { // 获取MD5实例 MessageDigest md = MessageDigest.getInstance("MD5"); // 使用标准UTF-8编码处理字符串,这是跨语言兼容的关键 byte[] digest = md.digest(data.getBytes(StandardCharsets.UTF_8)); // 使用传统的十六进制转换方法,确保格式一致性 StringBuilder hexString = new StringBuilder(32); // MD5固定32位 for (byte b : digest) { // 将字节转换为十六进制,确保始终是2位小写字母 hexString.append(String.format("%02x", b & 0xff)); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("SignUtils md5 algorithm not available", e); } } public static void main(String[] args) { String data = "撒大大"; System.out.println(md5(data)); } }

浙公网安备 33010602011771号