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  (发现$user是NULL值)
        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...

6年前 评论
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());
    }
6年前 评论
leo

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

6年前 评论
leo

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

6年前 评论
hookover

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

6年前 评论
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已被实例化正确

6年前 评论
leo

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

6年前 评论
hookover

@leo 非常感谢,我试试

6年前 评论
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
    }
}
6年前 评论
hookover

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

6年前 评论
hookover

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

6年前 评论
hookover

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

6年前 评论
hookover

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

6年前 评论

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