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文件中生成一个随机的secretsecret要注意保管,不能泄露。
.env文件在.gitignore文件中默认是被标记的,即.env文件是不建议上传到 github 上,同样也就不建议将secret上传到 github 上防止泄露。

$ php artisan jwt:secret

生成模型文件并执行迁移:

  1. 生成模型文件:

    $ php artisan make:model DemoModel -m

    -m表示同时生成模型对应的迁移文件。(数据库迁移是个重要知识点,不懂的自行学习

  2. 修改迁移文件:
    因为是学习/测试,因此我把程序最简化,只需要 namepassword 即可。
    对 jwt 使用的简单刨析(自定义Model)

  3. 执行迁移:

    $ php artisan migrate

修改模型文件:

对 jwt 使用的简单刨析(自定义Model)

修改内容:

  1. 必须 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 类实例。
    对 jwt 使用的简单刨析(自定义Model)

  2. 因为是学习/测试,因此我把程序最简化,只需要 namepassword 即可。

  3. 添加implements JWTSubject接口,并继承以下方法:

     public function getJWTIdentifier()
     {
         return $this->getKey();
     }
    
     public function getJWTCustomClaims()
     {
         return [];
     }

    我理解的含义是,将 JWTModel 进行映射,因为我们需要使用JWT生成token,而生成时需要传入JWTSubject实例对象,但实际我们传入的是 App\Models\DemoModel 实例对象,比如JWTAuth::fromSubject(instance of JWTSubject)

修改 Config 配置文件:

  1. 修改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::XXX vscode 编辑器会报错,这是因为编辑器并没有识别别名的特性,在报错下直接发请求,也是可以正常响应的。
    如果想直接use 长长的 path,可以不用添加这两行别名,因为有些编辑器会自动引入use XXX
  2. 修改auth.php配置文件:
    对 jwt 使用的简单刨析(自定义Model)
    对 jwt 使用的简单刨析(自定义Model)
  • 使用的守卫是api(因为我们前后端分离,路由是从/api进入的);
  • apidriver改为jwt
  • 既然我们要使用DemoModeleloquent,那么就要model=>App\Models\DemoModel::class

二、创建路由与控制器(简单起见这里不使用中间件)

  1. 创建路由:在routes/api.php
    对 jwt 使用的简单刨析(自定义Model)
    so easy!
  2. 创建控制器:
    $ 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()能输出更详细的内容。

四、测试

  1. 测试工具:postman
  2. 用户注册——服务端会生成token响应给客户端(postman):
    发送 Post 请求,注意 url 中必须加上/api/,这是因为我们使用的是routes/api.php

    不清楚api.phpweb.php的区别可以百度。

复制下面的token,不用复制引号。
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

  1. 用户登陆——客户端(postman)会携带token给服务器验证:
    把刚复制的token粘贴到这里:
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
    会响应true,可以点击Preview看的更清晰:
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

五、对 JWTAuth 类成员的简单刨析

fromSubject(JWTSubject $subject)

  1. 生成一个token。需传入的JWTSubject对象就是一个Model对象。

tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

fromUser(JWTSubject $user)

  1. fromSubject的别名,调用fromUser等于调用fromSubject:
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

$token

  1. 当前JWT实例中保存的token对象,非string类型。

getToken()

  1. 从当前JWT实例中获取token对象。
  2. $tokennull时会调用parseToken()函数解析Request中的token,之后再调用setToken()将解析后的token转换为token对象,最后将其存入$this->token中。
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

parseToken()

  1. 由上面的代码可知,第一步$this->parseToken()的返回值仍然是$this也就是说parseToken()函数的作用仅仅是给$this->token赋予一个有意义的token对象,当然如果赋予失败,则$this->token = null

setToken($token)

  1. 检查传入的Token对象|string是否满足【段数要求、令牌格式要求】,并将string类型转换成token对象。setToken()的返回值是$this,而并非token对象。
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
  2. parseToken()setToken()的区别在于parseToken()会先从Request中解析出token
  3. token对象成员很简单:$valuestring类型的tokenget()的作用就是返回value
    tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

check($getPayload = false)函数详解:

该函数上面的注释说Check that the token is valid.,但直接使用JWTAuth::check()时却会发现始终返回false,以为这是token本身的问题(过期了呀什么的)。我排查了很久才发现,这是因为发生异常时返回的是false!而并没有被进行抛出,这可真是令人尴尬…
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
我把源码的false改成$e,并使用JWTAuth::check()来验证token
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
注意这里不用var_dump()dd()函数,直接return JWTAuth::check(),这样看错误会更清楚一些。
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
会发现错误是在执行Tymon\JWTAuth\JWT->requireToken()这个函数时抛出的。
找到它:
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
这不就是上面介绍的$this->token吗…
原来在进行JWTAuth::check()前,我们需要对$this->token进行赋值。我在上面介绍过,parseToken()函数能给$this->token赋值,那就来尝试一下:

先把改过的源码改回来的:$e改回false

tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
postman返回了true
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)

这里使用了var_dump,不用会返回1,编程中true即1,false即0

我们再来测试一下错误token
先把要请求的token值随意增删改,
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
点击Send
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
返回了false

要调用验证方法就得需要写两行代码,这明显变得复杂了:
tymon/jwt-auth 的简单使用与浅度刨析(使用自定义Model)
因此我们通常使用:
JWTAuth::parseToken()->check();一行代码来验证请求发来的token

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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