Laravel JWT 的简单使用与浅度刨析(使用自定义Model)
一、安装与配置
安装:
使用最新的就行,使用时问题不在于版本,而在于你会不会读源码。
$ composer require tymon/jwt-auth
生成配置文件:
会在config文件夹中生成一个jwt.php文件。jwt.php可以配置一些加密算法、token过期时间等信息。
$php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
生成加密密钥:
token是由 header(base64算法加密) + payload(base64算法加密) + secret 再用HS256等算法加密后组成的。secret是服务器保存的,下面命令会在.env文件中生成一个随机的secret。secret要注意保管,不能泄露。.env文件在.gitignore文件中默认是被标记的,即.env文件是不建议上传到 github 上,同样也就不建议将secret上传到 github 上防止泄露。
$ php artisan jwt:secret
生成模型文件并执行迁移:
生成模型文件:
$ php artisan make:model DemoModel -m-m表示同时生成模型对应的迁移文件。(数据库迁移是个重要知识点,不懂的自行学习修改迁移文件:
因为是学习/测试,因此我把程序最简化,只需要name和password即可。
执行迁移:
$ php artisan migrate
修改模型文件:

修改内容:
必须
extends User这里as Authenticatable了。
该User类继承了许多接口,比如Authenticatable接口,JWT有部分功能使用到了 laravel 自带的Auth功能,比如JWTAuth::attempt()函数,这个函数是JWTAuth类调用的,而并不是Auth调用,但它的调用却需要Authenticatable类实例,因此如果不extends User的话,会抛出validateCredentials() must be an instance of Illuminate\Contracts\Auth\Authenticatable异常。
这也是为什么可以直接使用auth("api")->attempt(xxx)进行验证的原因。
如下:JWTAuth::attempt()函数中,byCredentials()函数需要Authenticatable类实例。
因为是学习/测试,因此我把程序最简化,只需要
name和password即可。添加
implements JWTSubject接口,并继承以下方法:public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; }我理解的含义是,将
JWT与Model进行映射,因为我们需要使用JWT生成token,而生成时需要传入JWTSubject实例对象,但实际我们传入的是App\Models\DemoModel实例对象,比如JWTAuth::fromSubject(instance of JWTSubject)。
修改 Config 配置文件:
- 修改
app.php配置文件:
给aliases添加以下两个字段:
添加该别名的好处是,能直接在头部'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class, 'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,use JWTAuth;便可使用JWTAuth::XXX,而无需use Tymon\JWTAuth\Facades\JWTAuth;长长的 path 。但你use JWTAuth;时会发现使用JWTAuth::XXXvscode 编辑器会报错,这是因为编辑器并没有识别别名的特性,在报错下直接发请求,也是可以正常响应的。
如果想直接use 长长的 path,可以不用添加这两行别名,因为有些编辑器会自动引入use XXX。 - 修改
auth.php配置文件:

- 使用的守卫是
api(因为我们前后端分离,路由是从/api进入的); - 将
api的driver改为jwt; - 既然我们要使用
DemoModel的eloquent,那么就要model=>App\Models\DemoModel::class。
二、创建路由与控制器(简单起见这里不使用中间件)
- 创建路由:在
routes/api.php下
so easy! - 创建控制器:
$ php artisan controller:DemoController
三、控制器(Controller)
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\DemoModel;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
class DemoController extends Controller
{
public function register(Request $request)
{
$credentials = [
'name' => $request->name,
'password' => $request->password
];
$dm = DemoModel::create($credentials);
if ($dm) {
// 生成 token
$token = JWTAuth::fromSubject($dm);
return var_dump($token);
}
}
public function login(Request $request)
{
// 验证 token
return var_dump((JWTAuth::parseToken()->check()));
}
}
var_dump()和dd()用法差不多,var_dump()能输出更详细的内容。
四、测试
- 测试工具:postman
- 用户注册——服务端会生成
token响应给客户端(postman):
发送 Post 请求,注意 url 中必须加上/api/,这是因为我们使用的是routes/api.php。不清楚
api.php和web.php的区别可以百度。
复制下面的
token,不用复制引号。
- 用户登陆——客户端(postman)会携带
token给服务器验证:
把刚复制的token粘贴到这里:
会响应true,可以点击Preview看的更清晰:
五、对 JWTAuth 类成员的简单刨析
fromSubject(JWTSubject $subject):
- 生成一个
token。需传入的JWTSubject对象就是一个Model对象。

fromUser(JWTSubject $user):
fromSubject的别名,调用fromUser等于调用fromSubject:
$token:
- 当前
JWT实例中保存的token对象,非string类型。
getToken():
- 从当前
JWT实例中获取token对象。 $token为null时会调用parseToken()函数解析Request中的token,之后再调用setToken()将解析后的token转换为token对象,最后将其存入$this->token中。


parseToken():
- 由上面的代码可知,第一步
$this->parseToken()的返回值仍然是$this。也就是说,parseToken()函数的作用仅仅是给$this->token赋予一个有意义的token对象,当然如果赋予失败,则$this->token = null。
setToken($token):
- 检查传入的
Token对象|string是否满足【段数要求、令牌格式要求】,并将string类型转换成token对象。setToken()的返回值是$this,而并非token对象。
parseToken()和setToken()的区别在于parseToken()会先从Request中解析出token。token对象成员很简单:$value为string类型的token,get()的作用就是返回value。
check($getPayload = false)函数详解:
该函数上面的注释说Check that the token is valid.,但直接使用JWTAuth::check()时却会发现始终返回false,以为这是token本身的问题(过期了呀什么的)。我排查了很久才发现,这是因为发生异常时返回的是false!而并没有被进行抛出,这可真是令人尴尬…
我把源码的false改成$e,并使用JWTAuth::check()来验证token:

注意这里不用var_dump()或dd()函数,直接return JWTAuth::check(),这样看错误会更清楚一些。
会发现错误是在执行Tymon\JWTAuth\JWT->requireToken()这个函数时抛出的。
找到它:
这不就是上面介绍的$this->token吗…
原来在进行JWTAuth::check()前,我们需要对$this->token进行赋值。我在上面介绍过,parseToken()函数能给$this->token赋值,那就来尝试一下:
先把改过的源码改回来的:
$e改回false。

postman返回了true!
这里使用了
var_dump,不用会返回1,编程中true即1,false即0
我们再来测试一下错误的token:
先把要请求的token值随意增删改,
点击Send:
返回了false!
要调用验证方法就得需要写两行代码,这明显变得复杂了:
因此我们通常使用:JWTAuth::parseToken()->check();一行代码来验证请求发来的token。
本作品采用《CC 协议》,转载必须注明作者和本文链接

关于 LearnKu
推荐文章: