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

如何通过PHP OAuth1实现Canonical MAAS REST API身份验证?

PHP对接Canonical MAAS REST API的OAuth1身份验证方案

我之前也踩过这个坑——MAAS的API密钥是consumer_key:token:secret三部分格式,而大部分PHP OAuth1示例只处理consumer key/secret和token/secret这两对,很容易让人摸不着头脑。其实MAAS的OAuth1实现是HMAC-SHA1的特殊变体,核心点就是consumer secret为空字符串,抓住这个就能顺利搞定。

下面给你两种可行的实现方式:


方式一:手动构建OAuth1请求(无需第三方库)

如果不想引入额外依赖,手动处理签名逻辑反而更直观:

<?php

// 替换为你的MAAS API密钥和服务器地址
$maasApiKey = 'your_maas_api_key_here';
$maasServerUrl = 'http://your-maas-server:5240/MAAS/api/2.0';

// 拆分API密钥的三个核心部分
list($consumerKey, $token, $tokenSecret) = explode(':', $maasApiKey);

// 要请求的API端点,比如获取所有机器列表
$apiEndpoint = '/machines/';
$fullUrl = $maasServerUrl . $apiEndpoint;

// 构建OAuth1基础参数,每个请求都要生成新的nonce和timestamp
$oauthParams = [
    'oauth_consumer_key' => $consumerKey,
    'oauth_token' => $token,
    'oauth_signature_method' => 'HMAC-SHA1',
    'oauth_timestamp' => time(),
    'oauth_nonce' => uniqid('', true), // 生成唯一随机字符串
    'oauth_version' => '1.0'
];

// 生成签名基字符串,必须严格按照RFC3986编码
$baseString = http_build_query($oauthParams, '', '&', PHP_QUERY_RFC3986);
$baseString = 'GET&' . rawurlencode($fullUrl) . '&' . rawurlencode($baseString);

// MAAS的consumer secret为空,所以签名密钥格式为 "&tokenSecret"
$signingKey = '&' . rawurlencode($tokenSecret);

// 生成HMAC-SHA1签名并base64编码
$signature = base64_encode(hash_hmac('sha1', $baseString, $signingKey, true));
$oauthParams['oauth_signature'] = $signature;

// 构建Authorization请求头
$authHeader = 'OAuth ' . http_build_query($oauthParams, '', ', ', PHP_QUERY_RFC3986);

// 发送GET请求
$ch = curl_init($fullUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, [$authHeader]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 如果是自签名证书的MAAS服务器,可临时跳过证书验证(生产环境不建议)
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// 处理响应
if ($httpCode === 200) {
    print_r(json_decode($response, true));
} else {
    echo "请求失败,状态码:$httpCode,响应内容:$response";
}
?>

关键注意事项:

  • 签名密钥必须带开头的&:OAuth1签名密钥规则是consumerSecret&tokenSecret,MAAS的consumer secret为空,所以必须保留&前缀
  • 每个请求必须生成新的oauth_nonce和oauth_timestamp,重复使用会导致签名验证失败
  • 所有参数必须用PHP_QUERY_RFC3986编码,避免特殊字符破坏签名逻辑

方式二:使用league/oauth1-client库(更规范)

如果项目已经用Composer管理依赖,推荐用league/oauth1-client封装OAuth1逻辑,只需自定义一个MAAS Server类即可:

1. 安装依赖

composer require league/oauth1-client

2. 实现自定义MAAS Server类

<?php

use League\OAuth1\Client\Server\Server;
use League\OAuth1\Client\Credentials\TokenCredentials;
use Psr\Http\Message\ResponseInterface;

class MAASServer extends Server
{
    // MAAS不需要临时凭证、授权页面和token获取流程,直接返回空字符串
    public function urlTemporaryCredentials(): string
    {
        return '';
    }

    public function urlAuthorization(): string
    {
        return '';
    }

    public function urlTokenCredentials(): string
    {
        return '';
    }

    // 示例:获取当前用户信息的端点
    public function urlUserDetails(): string
    {
        return $this->getConfig('base_url') . '/users/me/';
    }

    // 解析用户信息(根据MAAS的响应结构调整)
    public function userDetails($data, TokenCredentials $tokenCredentials): object
    {
        return (object) [
            'id' => $data['id'],
            'username' => $data['username'],
            'email' => $data['email']
        ];
    }

    public function userUid($data, TokenCredentials $tokenCredentials): string
    {
        return (string) $data['id'];
    }

    public function userEmail($data, TokenCredentials $tokenCredentials): ?string
    {
        return $data['email'] ?? null;
    }

    public function userScreenName($data, TokenCredentials $tokenCredentials): string
    {
        return $data['username'];
    }

    // 指定签名方法为HMAC-SHA1
    protected function signatureMethod()
    {
        return $this->createHmacSha1SignatureMethod();
    }

    // 自定义请求方法,方便调用任意MAAS API端点
    public function request(string $url, TokenCredentials $tokenCredentials, string $method = 'GET', array $parameters = []): ResponseInterface
    {
        $this->client->setBaseUrl('');
        return $this->createRequest($method, $url, $tokenCredentials, $parameters);
    }
}

3. 使用示例

<?php

require 'vendor/autoload.php';

// 配置MAAS信息
$maasConfig = [
    'identifier' => 'your_consumer_key_here', // API密钥的第一部分
    'secret' => '', // MAAS的consumer secret为空
    'base_url' => 'http://your-maas-server:5240/MAAS/api/2.0'
];

// 初始化Server
$maasServer = new MAASServer($maasConfig);

// 构建Token凭证(API密钥的第二、第三部分)
$tokenCredentials = new TokenCredentials();
$tokenCredentials->setIdentifier('your_token_here');
$tokenCredentials->setSecret('your_token_secret_here');

// 示例1:获取当前用户信息
try {
    $user = $maasServer->getUserDetails($tokenCredentials);
    echo "当前用户:{$user->username}({$user->email})";
} catch (Exception $e) {
    echo "获取用户信息失败:{$e->getMessage()}";
}

// 示例2:获取所有机器列表
try {
    $response = $maasServer->request($maasConfig['base_url'] . '/machines/', $tokenCredentials);
    $machines = json_decode($response->getBody(), true);
    print_r($machines);
} catch (Exception $e) {
    echo "获取机器列表失败:{$e->getMessage()}";
}

测试建议

先调用/users/me/端点验证身份是否成功,如果返回当前用户信息,说明签名逻辑正确。如果遇到401错误,优先检查:

  1. API密钥的三个部分是否拆分正确
  2. 签名密钥是否包含开头的&
  3. 请求头的OAuth参数编码是否符合规范
  4. MAAS服务器的API版本是否与请求端点匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 10:42:50