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

如何在Slim PHP中实现OAuth 2.0客户端凭证授权?

在Slim PHP里实现OAuth 2.0 Bearer Token授权验证

1. 先装依赖包

PHP生态里做OAuth2最常用的是league/oauth2-server,和Slim适配得很好,直接用Composer安装:

composer require league/oauth2-server

2. 配置OAuth2核心服务

新建一个配置文件(比如config/oauth2.php),初始化必要组件——你需要实现三个仓库接口来管理客户端信息、Token和权限范围,下面是简单的内存版示例(实际项目要换成数据库存储):

<?php
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\CryptKey;

// 客户端信息仓库,实际要从数据库读取
class InMemoryClientRepository implements ClientRepositoryInterface {
    public function getClientEntity($clientIdentifier) {
        $client = new \League\OAuth2\Server\Entities\ClientEntity();
        $client->setIdentifier('test-client'); // 你的测试客户端ID
        $client->setSecret('test-secret'); // 客户端密钥
        $client->setRedirectUri('http://example.com/callback');
        return $client;
    }
    // 按接口要求实现其他方法,比如validateClient
}

// Token仓库,实际要持久化到数据库
class InMemoryAccessTokenRepository implements AccessTokenRepositoryInterface {
    public function persistNewAccessToken(\League\OAuth2\Server\Entities\AccessTokenEntityInterface $accessToken) {}
    public function revokeAccessToken($tokenId) {}
    public function isAccessTokenRevoked($tokenId) { return false; }
}

// 权限范围仓库,按需实现
class InMemoryScopeRepository implements ScopeRepositoryInterface {
    public function getScopeEntityByIdentifier($scopeIdentifier) {
        $scope = new \League\OAuth2\Server\Entities\ScopeEntity();
        $scope->setIdentifier($scopeIdentifier);
        return $scope;
    }
    public function finalizeScopes(array $scopes, $grantType, \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity, $userIdentifier = null) {
        return $scopes;
    }
}

// 初始化授权服务器
$server = new AuthorizationServer(
    new InMemoryClientRepository(),
    new InMemoryAccessTokenRepository(),
    new InMemoryScopeRepository(),
    new CryptKey('file://path/to/your-private.key'), // 自己生成的RSA私钥路径
    getenv('OAUTH_ENCRYPTION_KEY') // 加密用的随机字符串,放环境变量里别硬写
);

// 启用客户端凭证授权模式(适合你测试的API场景)
$server->enableGrantType(
    new ClientCredentialsGrant(),
    new \DateInterval('PT1H') // Token有效期设1小时
);

return $server;

3. 添加获取Token的路由

在你的Slim应用里加一个/token接口,用来生成Bearer Token:

<?php
use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

require __DIR__ . '/vendor/autoload.php';

$app = AppFactory::create();

// 引入刚才的OAuth2配置
$oauthServer = require __DIR__ . '/config/oauth2.php';

// 获取Token的接口
$app->post('/token', function (Request $request, Response $response) use ($oauthServer) {
    try {
        return $oauthServer->respondToAccessTokenRequest($request, $response);
    } catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
        // 返回OAuth标准错误响应
        return $e->generateHttpResponse($response);
    } catch (\Exception $e) {
        $response->getBody()->write(json_encode(['error' => $e->getMessage()]));
        return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
    }
});

$app->run();

4. 写Token验证中间件

给需要保护的API加个中间件,每次请求都检查Header里的Bearer Token:

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class OAuth2Middleware {
    private $oauthServer;

    public function __construct($oauthServer) {
        $this->oauthServer = $oauthServer;
    }

    public function __invoke(Request $request, RequestHandler $handler): Response {
        try {
            // 验证Token,通过后会把客户端/用户信息附加到请求中
            $request = $this->oauthServer->validateAuthenticatedRequest($request);
            return $handler->handle($request);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
            $response = new \Slim\Psr7\Response();
            return $e->generateHttpResponse($response);
        } catch (\Exception $e) {
            $response = new \Slim\Psr7\Response();
            $response->getBody()->write(json_encode(['error' => '服务器出错了']));
            return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
        }
    }
}

把中间件加到需要保护的路由上:

// 受保护的API示例
$app->get('/api/protected', function (Request $request, Response $response) {
    // 可通过$request->getAttribute('oauth_client')获取客户端信息
    $response->getBody()->write(json_encode(['message' => '这是只有带有效Token才能访问的内容']));
    return $response->withHeader('Content-Type', 'application/json');
})->add(new OAuth2Middleware($oauthServer));

5. 实际项目注意事项

  • 仓库替换:示例用的内存仓库不能用于生产,必须换成数据库存储,保证客户端信息和Token的持久化。
  • 密钥安全:RSA私钥要妥善保管,别提交到代码仓库;加密密钥用环境变量管理,比如用vlucas/phpdotenv加载.env文件。
  • 授权模式扩展:如果需要用户登录授权(比如密码模式、授权码模式),给AuthorizationServer添加对应的Grant即可。
  • 测试方法:用Postman调用/token接口,传入client_id、client_secret和grant_type=client_credentials拿到Token,之后在请求受保护API时,Header里添加Authorization: Bearer {你的Token}即可正常访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:55:14