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

Java实现Pritunl Rest API认证遇401错误求解决方案

Pritunl API Java认证401错误修复方案

可能的问题点

  • 签名字符串未URL编码:Pritunl要求签名中的各个组件(API Token、时间戳、Nonce、请求方法、路径)需先进行URL编码,再用&拼接。你的代码直接拼接原始字符串,若包含特殊字符会导致签名不匹配。
  • 时间同步问题:Pritunl API对请求时间戳有5分钟的窗口限制,若本地服务器与Pritunl服务器时间差过大,会直接触发401。
  • 不必要的请求头:GET请求无需设置Content-Type: application/json,多余的头可能干扰认证逻辑。

修正后的示例代码

@Service
public class PritunlServiceImpl {

    private static final String API_URL = "https://xxxxxxxxxxxxxxxx";
    private static final String API_TOKEN = "xxxxxxxxxxxxxxxxxxxxxx";
    private static final String API_SECRET = "xxxxxxxxxxxxxxxxxxxxxx";
    private static final String HMAC_ALGORITHM = "HmacSHA256";

    public String getOrganization() throws Exception {
        String path = "/organization";
        String url = API_URL + path;
        String timestamp = String.valueOf(Instant.now().getEpochSecond());
        String authNonce = UUID.randomUUID().toString();

        // 对每个签名组件进行URL编码
        String encodedToken = URLEncoder.encode(API_TOKEN, StandardCharsets.UTF_8.name());
        String encodedTimestamp = URLEncoder.encode(timestamp, StandardCharsets.UTF_8.name());
        String encodedNonce = URLEncoder.encode(authNonce, StandardCharsets.UTF_8.name());
        String encodedMethod = URLEncoder.encode("GET", StandardCharsets.UTF_8.name());
        String encodedPath = URLEncoder.encode(path, StandardCharsets.UTF_8.name());

        // 按规则拼接签名字符串
        String authString = String.join("&", encodedToken, encodedTimestamp, encodedNonce, encodedMethod, encodedPath);

        // 生成HMAC-SHA256签名
        Mac mac = Mac.getInstance(HMAC_ALGORITHM);
        SecretKeySpec secretKey = new SecretKeySpec(API_SECRET.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM);
        mac.init(secretKey);
        byte[] hmacBytes = mac.doFinal(authString.getBytes(StandardCharsets.UTF_8));
        String authSignature = Base64.getEncoder().encodeToString(hmacBytes);

        // 构建请求头,移除不必要的Content-Type
        HttpHeaders headers = new HttpHeaders();
        headers.set("Auth-Token", API_TOKEN);
        headers.set("Auth-Nonce", authNonce);
        headers.set("Auth-Timestamp", timestamp);
        headers.set("Auth-Signature", authSignature);

        // 使用RestTemplate发起请求
        RestTemplate restTemplate = new RestTemplate();
        HttpEntity<String> request = new HttpEntity<>(headers);
        ResponseEntity<String> response = restTemplate.exchange(new URI(url), HttpMethod.GET, request, String.class);

        if (response.getStatusCode().is2xxSuccessful()) {
            return response.getBody();
        } else {
            throw new RuntimeException("Failed to fetch Organization: " + response.getStatusCode());
        }
    }
}

额外排查步骤

  • 验证服务器时间:确保本地服务器与Pritunl服务器时间同步(可通过系统时间校准工具或NTP服务调整)。
  • 检查API密钥:确认API_TOKEN和API_SECRET与Pritunl控制台生成的完全一致,无多余空格或字符。
  • 调试签名生成:将Java生成的签名字符串、时间戳、Nonce与Python版本的输出逐一对比,确认每一步的一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:55:11