hyperf 教程之 hyperf-auth 高级用法

前言

上次写了一个 hyperf-auth 组件,收到许多朋友的反馈和支持,非常感谢大家的支持。今天补充一下关于自定义用户认证的方法。
其实,大部分场景下你都可以通过 hyperf-auth 项目的 README 文档了解到具体如何使用 hyperf-auth 的各种功能,但是关于自定义验证,README 其实只是一笔带过。
hyperf 教程之 hyperf-auth 高级用法
下面我们就来了解以下具体如何实现自定义验证。

hyperf-auth 组件的设计思路

由于我本人是个 laravel 爱好者,所以整个组件的设计思路大致是跟 laravel auth 相似的,都有 guarduser provider,包括配置方式也是极其相似的,所以,扩展方式也是相似的。

自定义 guard

想要实现一个自己的 guard 非常简单,只要实现 Qbhy\HyperfAuth\AuthGuard 接口即可,而且我抽象了一个 AbstractAuthGuard 继承该抽象类可以减少许多代码,大部分情况下,你只需要实现下面这三个方法即可。

<?php

namespace App\Auth\Guard;

use Qbhy\HyperfAuth\Authenticatable;
use Qbhy\HyperfAuth\Guard\AbstractAuthGuard;

class CustomGuard extends AbstractAuthGuard
{
    public function login(Authenticatable $user)
    {
        // TODO: Implement login() method.
    }

    public function user(): ?Authenticatable
    {
        // TODO: Implement user() method.
    }

    public function logout()
    {
        // TODO: Implement logout() method.
    }
}

该类的构造方法可以注入一些 Hyperf 环境中常用的实例,比如 RequestSession。不重写构造函数的情况下,配置文件中的值和 guard 的属性对应关系如下:

$authConfig = [
    'default' => [
        'guard' => 'session',
        'provider' => 'users',
    ],
    'guards' => [
        'session' => [
            'driver' => Qbhy\HyperfAuth\Guard\SessionGuard::class,
            'provider' => 'users',
        ],
    ],
    'providers' => [
        'users' => [
            'driver' => \Qbhy\HyperfAuth\Provider\EloquentProvider::class,
            'model' => App\Model\User::class, //  需要实现 Qbhy\HyperfAuth\Authenticatable 接口
        ],
    ];
    /** @var SessionGuard $guard */
    var_dump($guard->name === 'session');  // true
    var_dump($guard->config === $authConfig['guards']['session']); // true 对应gaurds里面的value值
    var_dump($guard->userProvider); // 对应的UserProvider实例

当然,你也可以重写构造函数,用以注入你需要用到的实例,或者设置通过自定义配置创建的实例,下面用 JwtGuard 构造函数举例


    /** @var JWTManager */ 
    protected $jwtManager;

    /** @var RequestInterface */
    protected $request;

    /**
     * JwtGuardAbstract constructor.
     */
    public function __construct(
        array $config,
        string $name,
        UserProvider $userProvider,
        RequestInterface $request
    ) {
        parent::__construct($config, $name, $userProvider);
        $this->jwtManager = new JWTManager($config);
        $this->request = $request;
    }

自定义 user

有时候可能会给其他模型做认证功能,比如商家认证, 假设我们有 App\Model\Merchant 模型类,想要给商家加上登录认证功能,只需要实现 Qbhy\HyperfAuth\Authenticatable 接口即可。

<?php

declare (strict_types=1);

namespace App\Model;

use Hyperf\DbConnection\Model\Model;
use Qbhy\HyperfAuth\Authenticatable;

/**
 */
class Merchant extends Model implements Authenticatable
{
    public static function retrieveById($key): ?Authenticatable
    {
        // TODO: Implement retrieveById() method.
  }

    public function getId()
    {
        // TODO: Implement getId() method.
  }
}

通常情况下你只需要实现上面两个方法即可,如果你用来做授权字段就是主键的话,甚至直接使用 Qbhy\HyperfAuth\AuthAbility 这个 trait 就可以了,但是如果你用来做授权的是其他字段,比如 token 的话,就得自己实现这俩方法了

class Merchant extends Model implements Authenticatable
{
    use AuthAbility;
}

自定义 UserProvider

大部分情况下,开发者只需要定义模型并按照上面的方法实现 Authenticatable 接口就够用了,包括自定义数据源。如果你要实现更为复杂的自定义用户功能,这时候就需要自定义 UserProvider 了。你需要实现 Qbhy\HyperfAuth\UserProvider 接口。跟 自定义 guard 类似,我同样提供了一个抽象类,直接继承自这个抽象类即可,构造函数会传入 $name$config ,具体例子可以参考以下代码。

<?php

declare(strict_types=1);

namespace Qbhy\HyperfAuth\Provider;

use Qbhy\HyperfAuth\Authenticatable;

class EloquentProvider extends AbstractUserProvider
{
    public function retrieveByCredentials($credentials)
    {
        return call_user_func_array([$this->config['model'], 'retrieveById'], [$credentials]);
    }

    public function validateCredentials(Authenticatable $user, $credentials): bool
    {
        return $user->getId() === $credentials;
    }
}

该类同样允许重写构造函数注入你想要的实例

结语

至此,你已经学会了自定义 hyperf-auth 的相关用法了,其实用法还是和 laravel auth 差不多的,如果还有不懂的地方可以添加 QQ群: 873213948 向我提问。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 1年前 自动加精
qbhy
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 11
66

刚刚在看你的github 回头看到这个帖子。。

3年前 评论

强,点赞

3年前 评论
qbhy

@hedeqiang 谢谢

3年前 评论

分布式部署的情况下,有没有可用redis驱动?还是说要自己实现这个驱动

3年前 评论
qbhy

@大张 有这个驱动的,你看我写的例子。可以用下面这两个,

file

3年前 评论

@qbhy 你写的例子是在哪里呢

3年前 评论

没看懂真没用 :joy:

3年前 评论
qbhy (楼主) 2年前
qbhy

自己顶一顶

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!