zfr / zfr-oauth2-server
用于创建OAuth 2服务器的PHP库
Requires
- php: ^7.4 || ^8.0
- laminas/laminas-diactoros: ^2.6
- nesbot/carbon: ^2.62
- psr/container: ^1.0 || ^2.0
- psr/http-server-middleware: ^1.0
- ramsey/uuid: ^3.1 || ^4.0
- roave/security-advisories: dev-master
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.1
- laminas/laminas-coding-standard: ^2.4
- php-mock/php-mock-phpunit: ^2.6
- phpunit/phpunit: ^9.5.5
This package is auto-updated.
Last update: 2024-08-29 04:19:16 UTC
README
ZfrOAuth2Server是一个实现OAuth 2规范的PHP库。其主要目标是成为一个干净、PHP 7.0+库,旨在与任何持久层一起使用。它与PSR-7请求和响应兼容,这使得它可以与任何兼容PSR-7的框架一起使用。
目前,ZfrOAuth2Server没有实现整个规范(缺少隐式授权),因此如果您想了解ZfrOAuth2Server是否适用于您的应用程序,请查看文档。
然而,它实现了额外的令牌撤销规范。
以下是可以使用的其他OAuth2库
要求
- PHP 7.4或更高版本
待办事项
- 编写文档
- 安全审计
- 审查整个规范
- 更广泛地测试授权服务器
- 添加隐式授权
版本说明
请注意,直到我们达到1.0,我们将不会遵循语义版本。这意味着在0.1.x和0.2.x版本之间可能会发生BC变化。
完全重写的当前预发布版本不与先前实现兼容 - 考虑为EOL - 请参阅legacy-0.7分支。
请参阅变更日志
安装
使用Composer安装
php composer.phar require zfr/zfr-oauth2-server:^0.9-beta
支持
- 在https://github.com/zf-fr/zfr-oauth2-server/issues中提交问题。
- 在我们的gitter聊天中打招呼。
配置
一些Apache模块会删除HTTP授权头,如Authorization
,试图通过防止脚本看到敏感信息来增强安全性,除非开发人员明确启用此功能。
许多这些模块允许添加以下行到 .htaccess(或vhost目录指令)来允许这些头。
CGIPassAuth on
文档
ZfrOAuth2Server基于RFC 6749文档。
为什么使用OAuth2?
OAuth2是一种身份验证/授权系统,可以用于
- 实现无状态的身份验证机制(适用于API)
- 允许第三方安全地连接到您的应用程序
- 通过使用作用域来保护您的应用程序
OAuth2是一个密集、可扩展的规范,可以用于多种用途。截至今天,ZfrOAuth2Server实现了四个官方授权中的三个:AuthorizationGrant、ClientCredentialsGrant、PasswordGrant。此外还提供了一个RefreshTokenGrant来获取新的访问令牌。即将推出隐式授权和JWT令牌(需要帮助)。
OAuth2是如何工作的?
本文档旨在不详细解释OAuth2的工作原理。这里有一篇很好的参考资料您可以阅读。然而,这里是OAuth2工作原理的基本概念
- 资源所有者(您的JavaScript API、您的移动应用程序等)向授权服务器请求所谓的“访问令牌”。根据用例的不同,有几种策略,这些策略被称为“授权”。例如,“密码授权”假定资源所有者发送其用户名/密码。在所有情况下,您的授权服务器都会响应一个访问令牌(以及一个可选的刷新令牌)。
- 客户端将此访问令牌发送到对您的API进行的每个请求。由“资源服务器”使用它将此访问令牌映射到您系统中的用户。
选择授权类型取决于您的应用程序。以下是一些有关如何选择的提示
- 如果您是您API的唯一消费者(例如,您的JavaScript应用程序调用您的API),您应该使用“密码授权”。因为您信任您的应用程序,发送用户名/密码不是问题。
- 如果您想第三方代码连接到您的API,并且您确信该第三方可以保守秘密(这意味着客户端不是JavaScript API或移动应用程序):您可以使用客户端凭据授权。
- 如果您想第三方代码连接到您的API,而这些第三方应用程序无法保守秘密(例如,考虑一个非官方的Twitter客户端连接到您的Twitter账户),您应该使用授权授权。
使用授权服务器
授权服务器的目标是接受请求并生成令牌。授权服务器可以拒绝请求(例如,如果参数缺失或用户名/密码不正确)。
要使用授权服务器,您必须首先决定您想要支持哪种授权。一些应用程序可能只支持一种类型的授权,而其他应用程序可能支持所有可用的授权。这完全取决于您,您应该首先对这些授权有一个坚实的基础理解。例如,以下是创建仅支持授权的授权服务器的方法
$authTokenService = new TokenService($objectManager, $authTokenRepository, $scopeRepository); $accessTokenService = new TokenService($objectManager, $accessTokenRepository, $scopeRepository); $refreshTokenService = new TokenService($objectManager, $refreshTokenRepository, $scopeRepository); $authorizationGrant = new AuthorizationGrant($authTokenService, $accessTokenService, $refreshTokenService); $authorizationServer = new AuthorizationServer([$authorizationGrant]); // Response contains the various parameters you can return $response = $authorizationServer->handleRequest($request);
请求必须是一个有效的Psr\Http\Message\ServerRequestInterface
,授权服务器返回一个符合OAuth2规范的Psr\Http\Message\ResponseInterface
对象。
传递用户
大多数时候,您想要将访问令牌与用户关联起来。这是将令牌映射到您系统用户的唯一方法。为此,您可以将一个可选的第二个参数传递给handleRequest
。此类必须实现ZfrOAuth2\Server\Model\TokenOwnerInterface
接口
$user = new User(); // must implement TokenOwnerInterface // ... $response = $authorizationServer->handleRequest($request, $user);
AuthorizationServerMiddleware能够为您完成此操作并从(可配置的)请求属性中检索用户实例。这取决于您提供具有更高优先级的中间件,以将TokenOwnerInterface实例添加到请求属性中。
此类实现示例使用了LaminasAuthentication和Mezzio的TemplateRenderer。
final class OAuth2AuthorizationFlow
{
/**
* @var AuthenticationService
*/
private $authenticationService;
/**
* @var ClientService
*/
private $clientService;
/**
* @var TemplateRendererInterface
*/
private $template;
public function __construct(
AuthenticationService $authenticationService,
ClientService $clientService,
TemplateRendererInterface $template
) {
$this->authenticationService = $authenticationService;
$this->clientService = $clientService;
$this->template = $template;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $out = null)
{
if ($this->authenticationService->hasIdentity()) {
$request = $request->withAttribute('owner', $this->authenticationService->getIdentity());
}
if ($request->getMethod() === 'POST') {
$post = $request->getParsedBody();
$approved = filter_var($post['approved'], FILTER_VALIDATE_BOOLEAN);
if ($approved) {
return $out($request, $response);
}
}
$data = [];
$query = $request->getUri()->getQuery();
parse_str($query, $data['query']);
$data['client'] = $this->clientService->getClient($data['query']['client_id']);
return new HtmlResponse($this->template->render('app::oauth2/authorize-request', $data));
}
}
撤销令牌
ZfrOAuth2Server支持使用RFC 7009规范撤销访问和刷新令牌。您可以在授权服务器中使用handleRevocationRequest
方法。您必须传递以下两个POST参数
token
:要删除的令牌(无论是访问令牌还是刷新令牌)token_hint_type
:必须是access_token
或refresh_token
,以指示授权服务器撤销哪种类型的令牌。
如果您需要撤销为非公开客户端(这意味着具有秘密密钥的客户端)颁发的令牌,那么您必须使用客户端ID和密钥进行请求认证。
如果尝试撤销一个不存在的令牌,根据规范,它将返回200 SUCCESS请求。然而,如果令牌有效,但由于任何原因(例如数据库宕机)无法删除,则返回503 SERVICE UNAVAILABLE错误!
使用资源服务器
您可以使用资源服务器来检索访问令牌(通过自动从HTTP头中提取数据)。您还可以在检索令牌时指定作用域约束。
$accessTokenService = new TokenService($objectManager, $accessTokenRepository, $scopeRepository); $resourceServer = new ResourceServer($accessTokenService); if (!$token = $resourceServer->getAccessToken($request, ['write']) { // there is either no access token, or the access token is expired, or the access token does not have // the `write` scope }
ResourceServerMiddleware能够为您完成这项工作,只需在所有其他中间件之前运行它。
示例mezzio expressive路由配置。
[
'name' => 'command::commerce::create-store',
'path' => '/commerce/create-store',
'middleware' => [
ResourceServerMiddleware::class,
MyActionMiddleware::class,
],
'allowed_methods' => ['OPTIONS', 'POST'],
],
持久层
截至版本0.8-beta1,ZfrOAuth2Server已被重写以实现持久层无关。这意味着它可以与任何首选的持久层一起使用。
目前这些包提供了持久层;
- ZfrOAuth2ServerDoctrine 用于Doctrine 2