Designing Secure, Efficient, and Maintainable Third‑Party API Calls
The article outlines a comprehensive approach to third‑party API design, covering core principles such as security, reliability, usability and extensibility, detailed key‑management and authentication mechanisms, RESTful API specifications, implementation steps with code samples, and best‑practice recommendations for robust and maintainable integrations.
Why Third‑Party API Design Matters
Designing third‑party interfaces is a critical step for implementing system functionality. A secure, efficient, and easy‑to‑maintain call scheme protects system stability, data security, and user experience.
Basic Design Principles
Security : Prevent data tampering, expiration, and duplicate submissions.
Reliability : Ensure high availability under high concurrency and load.
Usability : Keep the interface simple so third‑party systems can call and maintain it easily.
Extensibility : Design with future expansion in mind, allowing new features or adjustments.
Design Scheme
1. API Key Generation and Management
AK (Access Key) : Public identifier used to label the application or user.
SK (Secret Key) : Confidential encryption key; AK and SK together authenticate requests.
2. Authentication Mechanism
Client Signature : Client builds a signature from AK and request parameters (path, method, params, timestamp, etc.) and places it in the request header.
Timestamp : Each request includes a current timestamp; the server typically accepts a window of 5 minutes.
Nonce (流水号) : A unique random number per request prevents replay attacks and duplicate submissions.
3. Callback Address
Third‑party applications must provide a callback URL to receive asynchronous notifications, ensuring reliable and timely data exchange.
4. API Design Details
URL Design : Use clear, descriptive paths, e.g., /api/resources for a resource list.
HTTP Methods : Define GET, POST, PUT, DELETE for respective operations.
Request Parameters : List required and optional fields with types and defaults.
Response Format : Uniform JSON structure containing status code, message, and data.
5. Permission and Authentication
appId : Unique identifier for the application.
appKey : Public key (account‑like) used to identify the app in requests.
appSecret : Private key (password‑like) for encryption and permission control.
token : Temporary token with an expiration time; obtained via appKey/appSecret during the first login and sent with subsequent requests.
6. appKey + appSecret Mechanism
First‑time verification : Use appKey and appSecret to request an access token.
Permission control : Different appKey/appSecret pairs can represent different permission levels (read‑only vs. read‑write).
7. Simplified Scenarios
Open APIs (e.g., Baidu, Google Maps): appId, appKey, and appSecret may be merged; appId is mainly for usage statistics.
Single‑permission configuration : When each user has only one permission set, appKey can be omitted and authentication relies on appId + appSecret.
Signature verification : Client sends appKey, timestamp, nonce, and sign (generated by SHA‑1/MD5 of appSecret + timestamp + nonce). Server recomputes the signature and compares it.
8. Signature Field Explanation
appId/appSecret : Unique identifiers and keys assigned to each caller.
timestamp : Server‑based time, typically valid for 5 minutes.
nonce : Temporary random number to prevent replay.
sign : Signature sent by the client for identity verification and tamper protection.
Concrete Implementation Steps
1. API Key Generation and Management
Generate keys using random strings or UUIDs to ensure uniqueness.
Store AK and SK in a database or persistent storage.
Distribute keys via UI, API, or self‑service registration.
Rotate SK regularly to reduce leakage risk.
public class ApiKeyGenerator {
public static String generateAccessKey() {
return UUID.randomUUID().toString();
}
public static String generateSecretKey() {
return Base64.getEncoder().encodeToString(new byte[16]);
}
}2. Interface Authentication
Two main methods are used:
Signature verification : Client creates a signature with AK and request parameters; server validates it.
Token verification : Client obtains a token using AK/SK; subsequent requests carry the token for validation.
public class SignAuthInterceptor implements HandlerInterceptor {
private String secretKey;
public SignAuthInterceptor(String secretKey) { this.secretKey = secretKey; }
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String timestamp = request.getHeader("timestamp");
String nonceStr = request.getHeader("nonceStr");
String signature = request.getHeader("signature");
if (isExpired(timestamp) || isNonceUsed(nonceStr)) {
throw new BusinessException("Invalid request");
}
String calculatedSignature = calculateSignature(request, secretKey);
if (!signature.equals(calculatedSignature)) {
throw new BusinessException("Invalid signature");
}
return true;
}
private boolean isExpired(String timestamp) {
long currentTime = System.currentTimeMillis() / 1000;
long requestTime = Long.parseLong(timestamp);
return currentTime - requestTime > 60; // 60 seconds validity
}
private boolean isNonceUsed(String nonceStr) {
// Check Redis or other store for reuse
return false;
}
private String calculateSignature(HttpServletRequest request, String secretKey) throws UnsupportedEncodingException {
Map<String, Object> params = new HashMap<>();
Enumeration<String> names = request.getParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
String value = request.getParameter(name);
if (!"signature".equals(name)) {
params.put(name, URLEncoder.encode(value, "UTF-8"));
}
}
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
StringBuilder sb = new StringBuilder();
for (String key : keys) {
sb.append(key).append("=").append(params.get(key)).append("&");
}
sb.append(secretKey);
return DigestUtils.md5DigestAsHex(sb.toString().getBytes("UTF-8"));
}
}3. API Design
Follow RESTful principles for URL, method, parameters, and response format.
@RestController
@RequestMapping("/api/resources")
public class ResourceController {
@GetMapping
public Result<List<Resource>> getResources(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int limit) {
List<Resource> resources = new ArrayList<>();
return Result.success(resources);
}
@PostMapping
public Result<Resource> createResource(@RequestBody Resource resource) {
return Result.success(resource);
}
@PutMapping("/{resourceId}")
public Result<Void> updateResource(@PathVariable String resourceId, @RequestBody Resource resource) {
return Result.success();
}
@DeleteMapping("/{resourceId}")
public Result<Void> deleteResource(@PathVariable String resourceId) {
return Result.success();
}
}
public class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("Success");
result.setData(data);
return result;
}
// getters and setters omitted
}4. Security Considerations
Use HTTPS to protect data in transit.
Server‑side request verification (signature, token).
Encrypt sensitive data with TLS.
Prevent replay attacks with nonce and timestamp checks.
public class AntiReplayInterceptor implements HandlerInterceptor {
private RedisTemplate<String, String> redisTemplate;
public AntiReplayInterceptor(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; }
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String nonceStr = request.getHeader("nonceStr");
String timestamp = request.getHeader("timestamp");
if (isNonceUsed(nonceStr) || isExpired(timestamp)) {
throw new BusinessException("Invalid request");
}
return true;
}
private boolean isNonceUsed(String nonceStr) { return redisTemplate.hasKey(nonceStr); }
private boolean isExpired(String timestamp) {
long currentTime = System.currentTimeMillis() / 1000;
long requestTime = Long.parseLong(timestamp);
return currentTime - requestTime > 60; // 60 seconds validity
}
}Best Practices for API Calls
Reasonable Token Use : Reduce username/password transmission by using tokens.
Error Handling : Gracefully handle network failures, parameter errors, etc.
Logging : Record request logs for troubleshooting and performance analysis.
Rate Limiting : Apply throttling to prevent abuse or malicious attacks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer1970
Formerly called 'Code to 35'. Add our main WeChat ID to access a wealth of shared resources (algorithms, interview prep, tech stacks: Java, Python, Go, big data). We mainly share serious development techniques, focusing on output-driven input. Occasionally we post life snippets and gossip. Our aim is to attract precise traffic and test advertising opportunities.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
