Lumen 中,如何为 JWT-AUTH 用到的 EloquentUserProvider 加上 Redis 缓存?

业务背景:
开发一个 api 登录获取 JWT 的接口,该接口预期秒每并发登录获取 token 会达到 100 + 请求且每个用户很可能会不断的获取 TOKEN (请不要让我对其做限制,这是业务允许的行为)
准备使用的包
jwt-auth lumen dingoapi https://github.com/liyu001989/lumen-api-de...**

过程:
因为对 laravel 和 lumen 都不是很熟悉,所以不太清楚 Auth 的整个验证过程,安装完 lumen api demo 后,我开始跟代码,\Auth::attempt ([用户名,密码]),发现它最后执行的文件是 vendor/tymon/jwt-auth/src/JWTGuard.php 中的 attempt,它是通过调用 hasValidCredenitals 进行验证的,继续跟

 protected function hasValidCredentials($user, $credentials)
 { dd($user);  ====> null  (发现$userNULL值)
        return $user !== null && $this->provider->validateCredentials($user, $credentials);
 }

我直接点击 validateCredentials 得到的是一个接口类,通过搜索找到 validateCredentials 实际执行的位置在
vendor/illuminate/auth/EloquentUserProvider.php 中,即:

    public function validateCredentials(Authenticatable as UserContract $user, array $credentials)
    {
       dd($user);  ==> App\Model\User对象,且$user$credentials对应的用户 
        $plain = $credentials['password'];
        return $this->hasher->check($plain, $user->getAuthPassword());
    }

当我点 UserContract 发现它也是一个接口,再搜索

问题
在这个过程中,我十分不理解的是:UserContract 是在哪里实例化的,实例化的具体文件是哪个文件?

需求
因为业务需要,我希望为 UserProvider 加一个 redis 缓存 ,以解决用户频繁获取 token 导致的频繁查数据库行为
因为前面跟的这个问题,我发现不仅要重写 UserProvider, 还要重写 UserContract,
但是这两个我都不会...
哪位大神可否指点一二,或提供一下相应解决方案的文档教程,感激!

hookover
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 13
leo

自定义 UserProvider 即可,参考 https://learnku.com/docs/laravel/5.5/authenticatio...

7年前 评论
hookover

@leo 我发现它这个 UserProvider 中的有个核心的验证方法,而这个验证方法才是从数据库生成数据的,应该要同时自定义这个方法才行,也即是下面代码中的 UserContract 对应 Illuminate\Contracts\Auth\Authenticatable,
上层调用这个函数的的时候,传的 $user 是 null, 在这个函数里,注入就进来的 user 就已经是目标对象了,真不知道怎么写...

public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials['password'];
        return $this->hasher->check($plain, $user->getAuthPassword());
    }
7年前 评论
leo

@vector 来自于同一个类的 retrieveById 方法

7年前 评论
leo

而你要做的实际上也应该是继承 EloquentUserProvider 类,但重写 retrieveById 方法,把由数据库读取改为 缓存 + 数据库 读取,别的方法不需要重写

7年前 评论
hookover

@leo 好的,我试试,非常感谢:clap: :clap: :clap:

7年前 评论
hookover

@leo 我在 api/vendor/illuminate/auth/EloquentUserProvider.php 文件中 的
public function retrieveById ($identifier) 函数及 public function retrieveByToken ($identifier, $token) 函数里面加入 dd () 代码,
但是发现两个函数都没有执行,
而我在 public function validateCredentials (UserContract $user, array $credentials) 函数里面加入 dd 是执行的,
且 $user 已被实例化正确

7年前 评论
leo

@vector 说错了,是 retrieveByCredentials 这个方法

7年前 评论
hookover

@leo 非常感谢,我试试

7年前 评论
hookover

@leo 看起来事情没还比较复杂,当我重载 EloquentUserProvider 后,程序会执行到这个函数,但是当我打印 $query->first () 时发现是空值。于是我尝试直接返回 null, 结果它响应到正确的结果了,由此看来还不止这个函数 需要重载… 所以,到目前为止,我仍然不知道是哪个文件的哪个函数生成的 User 实例……

class RedisAndEloquentUserProvider extends EloquentUserProvider
{
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials)) {
            return;
        }
        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.
        $query = $this->createModel()->newQuery();
        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, 'password')) {
                $query->where($key, $value);
            }
        }
//        return $query->first();
        return null;    //直接返回null, 与$query-first()执行结果是一样的,程序正确运行返回了登录后的token
    }
}
7年前 评论
hookover

经过进一步测试,我发现 $query->first () 在一段时间后会返回非空,并且必须返回非空,仍然没有搞明白是怎么回事情

7年前 评论
hookover

测试到现在 ,我 dd ($query->$first ()) 一直是 NULL,没有任何变化
于是我尝试直接 return null, 结果是一段时间是可以的,但一段里时间不行
只能返回 $query->first () 才可以,但打印 $query->first () 一直都是 null 啊?

7年前 评论
hookover

是我操作的错误,var_dump ($query->first ()) 有值

7年前 评论
hookover

这玩意极其不稳定……
var_dump ($query->first ()) 也 NULL 了……

7年前 评论