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

求助:使用PHP调用Pritunl API时增改操作返回401未授权

PHP调用Pritunl API时401 Unauthorized问题排查

我之前帮朋友解决过类似的问题——读操作正常但写操作返回401,大概率是请求签名的计算逻辑没处理好写请求的请求体。Pritunl的API采用AWS风格的HMAC认证,读请求(GET)通常没有请求体,签名计算相对简单,但写请求(POST/PUT)需要把请求体也纳入签名范围,这是很多PHP开发者容易忽略的点。

下面是具体的排查方向和解决方案:

1. 确认认证签名的计算逻辑是否正确

Pritunl的认证需要以下几个步骤,尤其是写请求必须包含请求体的哈希:

  • 获取当前Unix时间戳(秒级,注意服务器时间要和Pritunl服务器同步,时间差过大也会导致401)
  • 构造规范请求字符串:HTTP_METHOD\nAPI_PATH\nTIMESTAMP\nREQUEST_BODY(如果是GET请求,REQUEST_BODY为空字符串)
  • 使用API密钥的Secret作为密钥,对规范请求字符串做HMAC-SHA256加密,然后转成Base64编码得到签名
  • 设置请求头:
    • X-Pritunl-Timestamp: [TIMESTAMP]
    • Authorization: Pritunl [API_TOKEN]:[SIGNATURE]
    • Content-Type: application/json(写请求必须设置)

2. 完整的PHP示例代码

这里给你一个能处理读写请求的封装函数:

function pritunlApiRequest($apiUrl, $apiToken, $apiSecret, $method = 'GET', $body = null) {
    $timestamp = time();
    $path = parse_url($apiUrl, PHP_URL_PATH);
    
    // 构造规范请求
    $canonicalRequest = strtoupper($method) . "\n" . $path . "\n" . $timestamp . "\n";
    if ($body !== null) {
        $canonicalRequest .= $body;
    }
    
    // 计算签名
    $signature = base64_encode(hash_hmac('sha256', $canonicalRequest, $apiSecret, true));
    
    // 设置请求头
    $headers = [
        "X-Pritunl-Timestamp: {$timestamp}",
        "Authorization: Pritunl {$apiToken}:{$signature}",
        "Content-Type: application/json"
    ];
    
    // 初始化cURL
    $ch = curl_init($apiUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    
    // 处理写请求
    if ($method !== 'GET' && $body !== null) {
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    }
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    return [
        'code' => $httpCode,
        'data' => json_decode($response, true)
    ];
}

// 使用示例:创建用户
$apiToken = '你的API Token';
$apiSecret = '你的API Secret';
$apiUrl = 'https://your-pritunl-server.com/api/user';

$userData = json_encode([
    'name' => 'test_user',
    'email' => 'test@example.com',
    'password' => 'secure_password'
]);

$result = pritunlApiRequest($apiUrl, $apiToken, $apiSecret, 'POST', $userData);
print_r($result);

3. 常见坑点排查

  • 请求体必须是JSON字符串:不要直接传数组,一定要用json_encode()处理,并且确保没有语法错误
  • 时间同步问题:如果你的服务器和Pritunl服务器时间差超过5分钟,签名会失效,建议开启NTP同步
  • API权限验证:确认你的API Token拥有对应的写权限(比如创建用户、修改服务器的权限)
  • 路径大小写:Pritunl的API路径是区分大小写的,比如/api/user和/api/User是不同的

你可以对照这个示例检查你的代码,重点看写请求时是否把请求体加入了签名计算,这应该就是解决401问题的关键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:58:37