You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java调用Duo Security Admin API返回401错误,请求排查问题

Duo Security Admin API 401错误原因与修复方案

核心错误:认证方式不正确

你当前使用的Basic Auth(Base64编码密钥对)并非Duo Admin API要求的认证方式,Duo API需要基于HMAC-SHA1签名的自定义Authorization头,这是导致401未授权错误的根本原因。

错误细节说明

Duo Admin API的认证规则明确要求:

  • 禁止使用Basic Auth,必须生成HMAC-SHA1签名验证请求合法性
  • 签名需结合HTTP方法、请求路径、Date头、API主机名参数,用你的secretKey加密
  • Authorization头格式为:Duo <integrationKey>:<base64EncodedSignature>

修正后的Java代码

void users() {
    // Duo Admin API credentials and API hostname
    String integrationKey = "DI7ABPU9TUJQO14RET9Q";
    String secretKey = "YzDs7ZeQGMllravxDQxcn4jNAwyqF42P1XBDdGd2";
    String apiHostname = "api-d221a358.duosecurity.com";

    try {
        String usersPath = "/admin/v1/users";
        String usersUrl = "https://" + apiHostname + usersPath;
        URL url = new URL(usersUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        connection.setRequestMethod("GET");
        // 生成符合RFC 1123格式的Date头
        String dateHeader = OffsetDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME);
        connection.setRequestProperty("Date", dateHeader);
        connection.setRequestProperty("Content-Type", "application/json");

        // 生成Duo要求的HMAC-SHA1签名
        String signature = generateDuoSignature("GET", usersPath, dateHeader, apiHostname, secretKey);
        connection.setRequestProperty("Authorization", "Duo " + integrationKey + ":" + signature);

        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
                String inputLine;
                StringBuilder response = new StringBuilder();
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                System.out.println("List of Users: " + response.toString());
            }
        } else {
            System.out.println("Get Users request failed with HTTP response code: " + responseCode);
            // 读取错误响应详情辅助排查
            try (BufferedReader errIn = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
                String inputLine;
                StringBuilder errResponse = new StringBuilder();
                while ((inputLine = errIn.readLine()) != null) {
                    errResponse.append(inputLine);
                }
                System.out.println("Error details: " + errResponse.toString());
            }
        }
        connection.disconnect();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// 生成Duo API所需的HMAC-SHA1签名
private static String generateDuoSignature(String method, String path, String date, String host, String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
    // 拼接签名原始字符串:方法\n路径\n日期\n主机\n(POST请求需追加body内容,GET留空)
    String signatureString = String.join("\n", method, path, date, host, "");
    // 使用secretKey作为密钥执行HMAC-SHA1加密
    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
    byte[] hashBytes = mac.doFinal(signatureString.getBytes(StandardCharsets.UTF_8));
    // 加密结果Base64编码
    return Base64.getEncoder().encodeToString(hashBytes);
}

额外注意事项

  • 确保本地服务器时间与Duo服务器时间差在15分钟内,否则签名正确也会返回401
  • 核对integrationKey和secretKey的准确性,确认该集成具备访问/admin/v1/users接口的权限
  • 若为POST请求,签名字符串末尾需追加请求body的内容

内容的提问来源于stack exchange,提问作者Enamul Haque

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 06:22:44