OkHttp3调用使用Digest认证的接口

        OkHttp本身并不直接支持Digest认证,可以通过拦截器(Interceptor)来手动实现Digest认证的逻辑。

1、自定义Digest认证拦截器

@Slf4j
public class DigestAuthInterceptor implements Interceptor {
    @NotNull
    @Override
    @SneakyThrows
    public Response intercept(@NotNull Chain chain)  {
        Request original = chain.request();
        String ha1 = calculateHA1(USERNAME, REALM, PASSWORD);

        String method = original.method();
        String url = original.url().toString();
        String ha2 = calculateHA2(method, url);

        String nonce = generateNonce();
        String cNonce = generateNonce();
        String response = calculateResponse(ha1, nonce, NONCE_COUNT, cNonce, QOP, ha2);

        //构建Authorization头信息
        String authHeader = "Digest username=\"" + USERNAME + "\",realm=\"" + REALM + "\",nonce=\"" + nonce + "\",uri=\"" + url + "\",nc=" + NONCE_COUNT + ",cnonce=\"" + cNonce + "\",qop=" + QOP + ",response=\"" + response + "\"";
<think> 我们正在讨论使用JavaOkHttp库进行HTTP调用时,对header和body进行签名的方法。签名通常用于确保请求的完整性和身份验证。 常见的做法是使用某种算法(如HMAC-SHA256)对请求的关键部分(如请求头、请求体、时间戳等)生成一个签名,然后将签名放入请求头中(例如Authorization头)。 根据引用[1]中的配置,我们有不同的接口地址,但签名方法应该是通用的。 步骤: 1. 构建请求头和请求体。 2. 选取需要签名的要素,通常包括特定的请求头(如时间戳、请求体哈希等)和请求体本身。 3. 将选定的要素按照一定的规范拼接成字符串(例如,规范请求字符串)。 4. 使用密钥(通常由服务端提供)对规范字符串进行签名。 5. 将签名添加到请求头中(如Authorization头)。 下面是一个示例实现,假设我们需要对请求体进行签名,并包含时间戳和nonce(随机数)来防止重放攻击。 我们将使用以下步骤: - 生成时间戳(timestamp)和随机数(nonce)。 - 将请求体转换为字符串(如果请求体是JSON,则使用JSON字符串)。 - 构建待签名字符串:通常包括时间戳、nonce、请求方法、请求路径、请求体的哈希值(或其他需要签名的头)等。 - 使用HMAC-SHA256算法和密钥进行签名。 注意:具体签名规则需要根据接口提供方的要求来实现。这里我们假设一个常见的规则。 示例代码: </think> ### Java OkHttp调用中对Header和Body进行签名的实现方法 在使用OkHttp进行API调用时,对请求头和请求体进行签名是保证API安全性的常见做法。以下是完整实现方法: #### 一、签名原理 签名通常包含以下要素: 1. **时间戳**:防止重放攻击 2. **随机数(nonce)**:确保签名唯一性 3. **请求头关键字段**:如`Content-Type`, `User-Agent`等 4. **请求体摘要**:对body进行哈希处理 5. **签名算法**:常用`HMAC-SHA256` 签名流程伪代码: ```math \text{signature} = \text{HMAC-SHA256}(\text{secretKey}, \text{timestamp} + \text{nonce} + \text{header\_fields} + \text{body\_hash}) ``` #### 二、完整实现代码 ```java import okhttp3.*; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.UUID; public class SignedRequestExample { private static final String API_KEY = "your_api_key"; private static final String SECRET_KEY = "your_secret_key"; public static void main(String[] args) throws IOException { // 1. 创建请求体 MediaType JSON = MediaType.get("application/json; charset=utf-8"); String jsonBody = "{\"text\":\"需要识别的文本\"}"; RequestBody body = RequestBody.create(jsonBody, JSON); // 2. 生成签名所需参数 long timestamp = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString(); String bodyHash = sha256Hash(jsonBody); // 3. 构造签名 String signature = generateSignature(timestamp, nonce, bodyHash); // 4. 创建请求 Request request = new Request.Builder() .url("http://localhost:9000/ocr/general") .post(body) .addHeader("Content-Type", "application/json") .addHeader("X-Api-Key", API_KEY) .addHeader("X-Timestamp", String.valueOf(timestamp)) .addHeader("X-Nonce", nonce) .addHeader("X-Body-Hash", bodyHash) .addHeader("X-Signature", signature) .build(); // 5. 发送请求 OkHttpClient client = new OkHttpClient(); try (Response response = client.newCall(request).execute()) { System.out.println(response.body().string()); } } // SHA256哈希计算 private static String sha256Hash(String input) { try { java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hash); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } // 签名生成方法 private static String generateSignature(long timestamp, String nonce, String bodyHash) { try { // 构造签名字符串 String signString = timestamp + nonce + bodyHash; // 使用HMAC-SHA256加密 Mac hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), "HmacSHA256"); hmac.init(keySpec); byte[] signatureBytes = hmac.doFinal(signString.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(signatureBytes); } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException("签名生成失败", e); } } } ``` #### 三、关键实现说明 1. **请求头签名字段**: - `X-Timestamp`:请求发起时间戳 - `X-Nonce`:唯一随机数 - `X-Body-Hash`:请求体SHA256哈希值 - `X-Signature`:最终签名 2. **签名生成逻辑**: ```math \begin{align*} \text{signString} &= \text{timestamp} \| \text{nonce} \| \text{bodyHash} \\ \text{signature} &= \text{BASE64}(\text{HMAC-SHA256}(\text{secretKey}, \text{signString})) \end{align*} ``` 3. **签名验证流程**: - 服务端重新计算签名 - 验证时间戳有效性(防重放) - 检查nonce是否已使用 - 对比请求体哈希值 #### 四、最佳实践建议 1. **密钥管理**: - 使用环境变量或密钥管理系统存储密钥 - 避免在代码中硬编码密钥 2. **安全增强**: ```java // 添加HTTPS证书锁定 OkHttpClient client = new OkHttpClient.Builder() .certificatePinner(new CertificatePinner.Builder() .add("example.com", "sha256/AAAAAAAA...") .build()) .build(); ``` 3. **错误处理**: - 签名失败时返回401状态码 - 提供详细的错误信息头(如`X-Signature-Error`) 4. **性能优化**: - 复用OkHttpClient实例 - 使用连接池(默认已启用) 这种方法符合主流API安全规范(如AWS Signature V4),可有效防止请求篡改和重放攻击[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值