求助:使用PHP调用Pritunl API时增改操作返回401未授权
我之前帮朋友解决过类似的问题——读操作正常但写操作返回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
相关产品推荐
相关产品推荐

