AKSK接口没有固定的格式,不想basic、apikey等简单的认证方式,请求格式是固定的。最主要的就是AKSK签名认证的工具类以及服务端校验格式。
定义 AKSK 相关的常量和工具类
首先,我们创建一些常量来表示访问密钥(AK)和秘密密钥(SK),以及用于签名的算法(这里使用 HMAC - SHA256)。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class AkskUtils {
// 模拟的访问密钥(AK)
public static final String ACCESS_KEY = "your_access_key";
// 模拟的秘密密钥(SK)
public static final String SECRET_KEY = "your_secret_key";
// 签名算法
public static final String SIGNATURE_ALGORITHM = "HMACSHA256";
public static String calculateSignature(String data) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance(SIGNATURE_ALGORITHM);
SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), SIGNATURE_ALGORITHM);
mac.init(secretKeySpec);
byte[] signatureBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return bytesToHex(signatureBytes);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
客户端实现
客户端负责构造请求,并添加鉴权相关的信息(如签名)到请求中。
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.time.Duration;
public class AkskClient {
public static void main(String[] args) throws IOException, InterruptedException, NoSuchAlgorithmException, InvalidKeyException {
// 构造请求数据,这里简单模拟一个查询参数
String queryParam = "param1=value1¶m2=value2";
String requestData = "GET&/api/resource?" + queryParam;
// 计算签名
String signature = AkskUtils.calculateSignature(requestData);
// 构造完整的请求URL,添加签名作为查询参数
String url = "http://localhost:8080/api/resource?" + queryParam + "&signature=" + signature;
// 构造HTTP请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Access-Key", AkskUtils.ACCESS_KEY)
.timeout(Duration.ofSeconds(5))
.build();
// 发送请求
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyAndForestResponse<String>);
// 处理响应
System.out.println("Response status code: " + response.statusCode());
System.out.println("Response body: " + response.body());
}
}
服务端实现
服务端负责接收客户端的请求,验证请求中的鉴权信息(如访问密钥和签名)是否合法。
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
public class AkskServer {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
// 创建HTTP服务器,监听在本地的8080端口
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
// 设置请求处理程序
server.createContext("/api/resource", new MyHandler());
// 启动服务器
server.start();
System.out.println("Server started on port 8080");
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
// 获取请求的查询参数
String query = exchange.getRequestURI().getQuery();
String[] queryParams = query.split("&");
// 提取访问密钥、签名和其他参数
String accessKey = null;
String signature = null;
String requestData = null;
for (String param : queryParams) {
if (param.startsWith("Access-Key=")) {
accessKey = param.substring("Access-Key=".length());
} else if (param.startsWith("signature=")) {
signature = param.substring("signature=".length());
} else {
requestData = (requestData == null)? param : requestData + "&" + param;
}
}
// 验证访问密钥是否正确
if (!AkskUtils.ACCESS_KEY.equals(accessKey)) {
sendErrorResponse(exchange, 401, "Invalid access key");
return;
}
// 重新计算签名,用于和客户端传来的签名对比
String calculatedSignature = AkskUtils.calculateSignature(requestData);
// 验证签名是否正确
if (!calculatedSignature.equals(signature)) {
sendErrorResponse(exchange, 403, "Invalid signature");
return;
}
// 如果鉴权通过,发送成功响应
sendSuccessResponse(exchange);
}
private void sendErrorResponse(HttpExchange exchange, int statusCode, String message) throws IOException {
byte[] errorBytes = message.getBytes();
exchange.sendResponseHeaders(statusCode, errorBytes.length);
OutputStream os = exchange.getResponseBody();
os.write(errorBytes);
os.close();
}
private void sendSuccessResponse(HttpExchange exchange) throws IOException {
byte[] successBytes = "Authenticated successfully".getBytes();
exchange.sendResponseHeaders(200, successBytes.length);
OutputStream os = exchange.getResponseBody();
os.write(successBytes);
os.close();
}
}
}
实际应用中可能需要更复杂的处理,比如对请求数据的更规范整理、更好的错误处理、更安全的密钥管理等,但大致思想就是这样的。