lookyman/nette-oauth2-server-doctrine

此包已被弃用且不再维护。未建议替代包。

Nette 框架中集成 The League of Extraordinary Packages' OAuth 2.0 服务器 - Kdyby/Doctrine 存储实现

3.0.2 2019-11-28 12:21 UTC

This package is auto-updated.

Last update: 2024-05-04 15:59:34 UTC


README

将 The League of Extraordinary Packages' 非凡包OAuth 2.0 服务器 集成到 Nette 框架 中 - Kdyby/Doctrine 存储实现。

Build Status Scrutinizer Code Quality Coverage Status Downloads Latest stable

安装

无聊的部分

阅读 这篇文档。从头到尾,真的,不要跳过它然后回来抱怨某些东西不起作用。

如果您尚未安装和配置 Kdyby/Doctrine,请务必安装。

使用 Composer 进行安装

composer require lookyman/nette-oauth2-server-doctrine

设置路由

根据您想要支持的授权类型,您必须设置路由到 access_tokenauthorize 或这两个端点。

  • 对于除 隐式 之外的所有授权,设置 access_token 端点路由。
  • 对于 授权码隐式 授权,设置 authorize 端点路由。

端点位于 NetteOAuth2Server:OAuth2:accessTokenNetteOAuth2Server:OAuth2:authorize 映射,设置可能如下所示

class RouterFactory
{
    /**
     * @return IRouter
     */
    public static function createRouter()
    {
        $router = new RouteList();
        $router[] = new Route('oauth2/<action>', 'NetteOAuth2Server:OAuth2:default');
        // ...
        return $router;
    }
}

您可以通过 https://myapp.com/oauth2/access-tokenhttps://myapp.com/oauth2/authorize URL 分别访问这些端点。

配置

extensions:
    oauth2: Lookyman\NetteOAuth2Server\Storage\Doctrine\NetteOAuth2ServerDoctrineExtension
    
oauth2:
    grants:
        authCode: on
        clientCredentials: on
        implicit: on
        password: on
        refreshToken: on
    privateKey: /path/to/private.key
    publicKey: /path/to/public.key
    encryptionKey: '32 base64encoded random bytes'
    approveDestination: :Approve:
    loginDestination: :Sign:in
    tablePrefix: nette_oauth2_server_
    loginEventPriority: 0

grants 部分包含您想要启用的授权。默认情况下,它们都是禁用的,因此您只需输入您想要使用的内容。每个值不必只是一个布尔值。您可以指定一个令牌 TTL,例如:[ttl: PT1H]。其中两种授权还有额外的设置。《授权码》授权有 authCodeTtl 选项,而《隐式》授权有 accessTokenTtl 选项。在这些情况下,指定间隔的格式遵循 此处 描述的格式。

《授权码》授权还有一个选项来启用对 RFC 7636 的支持。您可以通过指定 [pkce: on] 来打开它。

接下来,您需要一对私钥/公钥。如果您没有跳过第一步,您应该知道如何进行。如果您跳过了,现在是时候了。去读它,拿到密钥后再回来,并在 privateKeypublicKey 选项中输入路径。如果您的私钥受密码保护,请按照以下方式指定:privateKey: [keyPath: /path/to/private.key, passPhrase: passphrase]

此外,您还需要提供一个加密密钥。最简单的方法是从终端运行 php -r 'echo base64_encode(random_bytes(32));' 并将结果粘贴到 encryptionKey 选项中。

如果您正在使用Authorization CodeImplicit授权,您需要设置重定向目的地。这些应该是您在$presenter->redirect()方法中使用的普通字符串。下面将详细讨论approveDestinationloginDestination应指向包含应用程序登录表单的presenter/action。两个路径都应该是绝对路径(带有模块)。

如果您不使用Authorization CodeImplicit授权,可以省略approveDestinationloginDestination选项。

tablePrefix选项允许您设置生成表的表前缀。默认值是nette_oauth2_server_

最后,当使用Authorization CodeImplicit授权时,用户会在某个时刻被重定向到登录页面。这种重定向是通过监听Nette\Security\User::onLoggedIn事件的订阅者来完成的,但如果您已经有其他订阅者正在监听它,您可能需要调整事件优先级。您可以使用loginEventPriority选项来做到这一点。

更新数据库模式

php www/index.php orm:schema-tool:update --force

您可能希望使用--dump-sql而不是--force,并手动运行生成的SQL查询。但如果您的数据库模式之前与映射同步,这应该是安全的。

它将在数据库中生成7个新表

  • nette_oauth2_server_access_token
  • nette_oauth2_server_access_token_scope
  • nette_oauth2_server_auth_code
  • nette_oauth2_server_auth_code_scope
  • nette_oauth2_server_client
  • nette_oauth2_server_refresh_token
  • nette_oauth2_server_scope

实现特性

最后一部分(也是最有趣的部分)是将所有这些集成到您的应用程序中。为此,有一个方便的特性可以轻松完成这个过程。此外,此步骤仅适用于您想使用Authorization CodeImplicit授权的情况,所以如果您不这样做,您已经完成了。太棒了!

您需要创建一个批准presenter。还记得配置中的approveDestination选项吗?这就是它的作用。presenter应使用Lookyman\NetteOAuth2Server\UI\ApprovePresenterTrait特性,并在approveDestination选项指向的动作中调用$this['approve']。它应该看起来像这样

class ApprovePresenter extends Presenter
{
    use ApprovePresenterTrait;
    
    // ...

    public function actionDefault()
    {
        $this['approve'];
    }
}

当然,您不必为此创建一个新的presenter。如果您愿意,可以在现有的presenter中使用此特性。只需确保在配置中设置正确的approveDestination并在动作中初始化组件为$this['approve']即可。

最后,该动作需要一个模板。因此,在presenter的动作正确目的地创建一个Latte模板文件,并将其中的单行放在里面

{control approve}

如你所见,整个过程高度可配置。这样做是为了让您完全控制自己的应用程序,并将艰苦的工作留给包。

完成设置

此包不提供管理客户端应用程序、访问令牌或作用域的方法。您必须自己实现这些。但是,您可以使用此包提供的实体和存储库。

  • 访问令牌
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\AccessToken\AccessTokenEntity
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\AccessToken\AccessTokenRepository
  • 认证代码
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\AuthCode\AuthCodeEntity
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\AuthCode\AuthCodeRepository
  • 客户端
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\Client\ClientEntity
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\Client\ClientRepository
  • 刷新令牌
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\RefreshToken\RefreshTokenEntity
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\RefreshToken\RefreshTokenRepository
  • 作用域
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\Scope\ScopeEntity
    • Lookyman\NetteOAuth2Server\Storage\Doctrine\Scope\ScopeRepository

至少,您应该创建一种注册客户端应用程序的方法。除非您只想手动在数据库中完成。

保护资源

本软件包提供了一个抽象的 Lookyman\NetteOAuth2Server\UI\ResourcePresenter,您可以使用它来保护您的资源。它的 checkRequirements() 方法验证访问令牌,并使用修改后的 Psr\Http\Message\ServerRequestInterface 对象触发一个 onAuthorized 事件。如果验证成功,以下属性将被设置在它上面:

  • oauth_access_token_id - 访问令牌标识符,
  • oauth_client_id - 客户端标识符,
  • oauth_user_id - 由访问令牌表示的用户标识符,
  • oauth_scopes - 字符串作用域标识符数组。

高级使用

自定义审批模板

审批组件的模板已准备好使用 Bootstrap,但可以通过一些特质魔法进行更改

class ApprovePresenter extends Presenter
{
    use ApprovePresenterTrait {
        createComponentApprove as ___createComponentApprove;
    }
    
    // ...
    
    /**
     * @return ApproveControl
     */
    protected function createComponentApprove()
    {
        $control = $this->___createComponentApprove();
        $control->setTemplateFile(__DIR__ . '/path/to/template.latte');
        return $control;
    }
}

模板传递一个变量 $authorizationRequest,其中包含一个 League\OAuth2\Server\RequestTypes\AuthorizationRequest 对象,其中包含有关正在批准的请求的信息。

自定义授权

自定义授权必须实现 League\OAuth2\Server\Grant\GrantTypeInterface。在您的 config.neon 中启用它们,如下所示

services:
    - MyCustomGrant
    oauth2.authorizationServer:
        setup:
            - enableGrantType(@MyCustomGrant)

日志记录

此软件包支持标准 PSR-3 日志记录。如果您已注册符合规范的记录器作为服务,则最简单的方法是通过 config.neon 启用它

decorator:
    Psr\Log\LoggerAwareInterface:
        setup:
            - setLogger

客户端密钥验证

默认情况下,Lookyman\NetteOAuth2Server\Storage\Doctrine\Client\ClientRepository 使用简单的 hash_equals 函数来验证客户端密钥。这意味着它期望数据库中的密钥以纯文本形式存储,这可能是出于明显的原因而并非最佳选择。因此,强烈建议您将密钥哈希化(例如使用 password_hash()),并实现您自己的密钥验证器

class SecretValidator
{
    public function __invoke($expected, $actual)
    {
        return password_verify($actual, $expected);
    }
}

然后在配置中注册它

services:
    - SecretValidator
    oauth2.repository.client:
        arguments: [secretValidator: @SecretValidator]

用户凭据验证

Lookyman\NetteOAuth2Server\User\UserRepository 通过尝试登录用户来验证用户凭据。但是,如果您的登录过程以某种方式被修改,它可能会以意外的方式轻松失败。在这种情况下,您可能需要重新实现凭据验证器。只需以您应用程序的方式获取正确的用户 ID,然后返回 Lookyman\NetteOAuth2Server\User\UserEntity(或 null,如果凭据无效)。

class CredentialsValidator
{
    public function __invoke($username, $password, $grantType, ClientEntityInterface $clientEntity)
    {
        // get the user ID from your application, and
        return new UserEntity($userId);
    }
}

然后在配置中注册它

services:
    - CredentialsValidator
    oauth2.repository.user:
        arguments: [credentialsValidator: @CredentialsValidator]

修改作用域

在颁发访问令牌之前,您可以修改请求的作用域。默认情况下,令牌将使用请求的作用域颁发,但您可以使用自定义终结器更改这一点

class ScopeFinalizer
{
    public function __invoke(array $scopes, $grantType, ClientEntityInterface $clientEntity, $userIdentifier)
    {
        return $scopes; // this is the default behavior
    }
}

然后在配置中注册它

services:
    - ScopeFinalizer
    oauth2.repository.scope:
        arguments: [scopeFinalizer: @ScopeFinalizer]