如何在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
相关产品推荐
相关产品推荐

