Laravel快速接入JWT用户认证(多用户认证)tymon/jwt-auth

article/2025/9/14 17:06:29

JWT应用

  • 创建新项目
  • 安装
  • 快速接入
    • 创建 Token
  • 完成接口
  • 多用户认证
    • 创建 Admin

JWT 是 JSON Web Token 的缩写,它是一个规范,让用户和服务器之间传递安全可靠的信息。

创建新项目

创建一个 Laravel的新项目,我们依然推荐大家使用 LTS 的版本:

composer create-project --prefer-dist laravel/laravel laravel-test
  • 配置站点并修改 host文件
  • 修改一下 env

创建一下基础的数据表。

php artisan migrate

这样项目就可以正常访问了。

安装

安装一下扩展包tymon/jwt-auth

composer require tymon/jwt-auth

不发布配置也是可以使用的,可以直接通过 env 变量修改,为了方便之后的讲解,我们发布出出来。

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

执行一下 jwt:secret,这个命令会在 env 中增加一个 JWT_SECRET,同我们的 APP_KEY 这个 secret 是十分重要的,用于给 Token 签名,更换这个 secret 会导致之前生成的所有 Token 无效,所以不要随意的更换这个secret

php artisan jwt:secret

快速接入

创建 Token

修改一下 User 模型,需要实现扩展包提供的接口 Tymon\JWTAuth\Contracts\JWTSubject,接口要求我们实现两个方法:

getJWTIdentifier —— 返回模型的 id,一般直接使用 $this->getKey() 返回模型主键。
getJWTCustomClaims —— 返回数组,存放自定义的数据用于放在 Token 中,可以先返回空数组。

app/Models/UserModel.php

<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;class UserModel extends Authenticatable implements JWTSubject
{use HasFactory, Notifiable;protected $table = 'users';public $timestamps = false;public function getJWTIdentifier(){return $this->getKey();}public function getJWTCustomClaims(){return [];}
}

这样就可以创建 Token 了,测试一下,打开 Tinker:

$user = User::find(1);
JWTAuth::fromUser($user);

找到 ID 为 1 的用户,使用 JWTAuth::fromUser 为这个用户创建一个 JWT。

在这里插入图片描述

可以看到这个很长的字符串就是一个 JWT 了,看一下它的结构,使用 base64_decode 可以解码这个字符串,或者我们直接去jwt.io解码看的更加清楚:

在这里插入图片描述

JWT 由头部(header)、载荷(payload)与签名(signature)组成,一个 JWT 类似下面这样:

{"typ":"JWT","alg":"HS256"
}
{"iss": "http://package.test","iat": 1536052439,"exp": 1536056039,"nbf": 1536052439,"jti": "UIbnBVxa2K77MCMK","sub": 1,"prv": "87e0af1ef9fd15812fdec97153a14e0b047546aa"
}
signature
  • 头部申明了加密算法;
  • 载荷中中记录了一些关键数据:
    • iss:—— 签发者,也就是 package.test ;
    • iat—— 签发时间;
    • exp—— 过期时间;
    • nbf —— 在这个时间之前,该 JWT 都是不可用的,一般同签发时间 iat;
    • jti—— 唯一标识符,防止重放攻击。
    • sub—— 用户标识,这里是用户 ID
    • prv—— 扩展包自定义字段,模型名的哈希值,等于sha1(‘App\User’),用于区别不同的模型,下面的课程会深入介绍。
  • 最后的 signature 是由服务器进行的签名,保证了 token 不被篡改。

JWT 最后是通过 Base64 编码的,也就是说,它可以被翻译回原来的样子来的。所以不要在 JWT 中存放一些敏感信息。

用户 id,过期时间等数据都保存在 Token 中了,所以并不需要将 Token 保存在服务器中,客户端请求的时候在 Header 中携带 Token,服务器获取 Token 后,进行 base64_decode 解码即可获取数据进行校验,由于已经有了签名,所以不用担心数据被篡改。

结合 Laravel Auth

一般我们希望通过 Laravel 的用户认证系统Auth::guard来完成相关的功能,而不是直接使用扩展包提供的门面 JWTAuth,修改一下相关配置:

config/auth.php

'guards' => ['web' => ['driver' => 'session','provider' => 'users',],'api' => ['driver' => 'jwt','provider' => 'users',],
],'providers' => ['users' => ['driver' => 'eloquent','model' => App\Models\UserModel::class,],
],

apidrivertoken 改为 jwt,继续使用 tinker 测试一下,注意修改了代码要重启 tinker

$credentials = ['email' => '1102389095@qq.com', 'password' => 'secret'];
auth('api')->attempt($credentials);

注意替换上面的 email 为你数据库中的邮箱,我们定义了一个 $credentials,这个数组对应了请求提交过来的用户名以及密码,最后使用 attempt 来验证是否正确,验证成功会返回一个 JWT。

使用任意用户标识和用户密码,都可以作为验证参数。

完成接口

对于 API 来说一般需要以下几个接口:

  • login —— 用户登录,获取 JWT;
  • refresh—— 刷新 JWT;
  • logout —— 退出登录,注销 JWT;
  • user —— 获取当前 JWT 对应的用户。

当然你可能有自己的接口命名规范,我们这里只是讲解扩展包的使用,就直接使用扩展包文档中的命名了。这里可能会有疑惑的是 refresh 和 logout 两个接口,稍微解释一下:

  • 刷新 JWT
    任何一个永久有效的 token 都是相当危险的,通过任意方式泄露了 token 之后,用户的相关信息都有可能被利用。所以为了安全考虑,任何一种令牌的机制,都会有过期时间,过期时间一般也不会太长,可能几个小时或者几天。那么 token 过期以后,难道要用户重新登录吗?像 OAuth 2.0 有 refresh_token 可以用来刷新一个过期的 access_token,jwt-auth 同样也为我们提供了刷新的机制,只要在可刷新的时间范围内,即使 JWT 过期了,依然可以调用接口,换取一个新的 JWT。这对于客户端长期保持用户登录状态是十分重要的。我们需要了解两个时间

    • jwt.ttl (JWT_TTL) —— 多长时间以后 JWT 就过期了 (单位分钟);
    • jwt.refresh_ttl (JWT_REFRESH_TTL) —— 多长时间以内, JWT 可以再次被刷新(单位分钟)。

一般情况下 refresh_ttl 应该大于 ttl,也就是 JWT 过期以后,依然可以刷新一个新的 JWT。

  • 删除 JWT
  • 用户退出登录的时候,是需要将当前这个 JWT 注销的,但是 JWT 本身不用存储在服务端,因为本身已经包含了足够的信息以及签名,那如何来完成注销呢?其实是利用了黑名单,删除只是将 JWT 加入黑名单(Laravel 缓存)而已,加入黑名单的 JWT 都是无法继续使用的。

routes/api.php

use Illuminate\Http\Request;Route::post('login', function (Request $request) {$credentials = $request->only('email', 'password');if (!$token = auth('api')->attempt($credentials)) {return response()->json(['error' => 'Unauthorized'], 401);}return response()->json(['token' => $token]);
});Route::post('refresh', function () {return response()->json(['token' => auth('api')->refresh()]);
});Route::post('logout', function () {auth('api')->logout();return response()->json(null, 204);
});

使用 PostMan 测试一下:

login 获取 JWT:

在这里插入图片描述

获取对应的用户,只需要将 JWT 放在 header 中,PostMan 可以填写在 Bearer Token 中:

在这里插入图片描述

刷新 JWT,注意刷新过之后,之前的 JWT 会被加入黑名单,也就不能继续使用了:

在这里插入图片描述

删除 JWT:

在这里插入图片描述

上面的代码应该很容易理解,你可以尝试一下优化一下,把方法写入 Controller,增加 Request 验证请求参数,返回合理的数据,等等。

多用户认证

创建 Admin

当我们的项目中需要为多个模型创建 Token,不同的 Token 可以使用不同的接口,这样的场景该如何处理呢?先来增加一个模型以及数据表。

php artisan make:model Admin -fm

-fm 参数是同时创建 migration 文件以及 factory 文件。

在这里插入图片描述

让 admins 与 users 拥有相同的字段:

database/migrations/< yourdate >createadminstable.php

<?phpuse Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;class CreateAdminsTable extends Migration
{/*** Run the migrations.** @return void*/public function up(){Schema::create('admins', function (Blueprint $table) {$table->increments('id');$table->string('name');$table->string('email')->unique();$table->string('password');$table->rememberToken();$table->timestamps();});}/*** Reverse the migrations.** @return void*/public function down(){Schema::dropIfExists('admins');}
}

修改 Admin 模型:

app/Models/AdminModel.php

<?phpnamespace App;use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;class Admin extends Authenticatable implements JWTSubject
{use Notifiable;protected $table = 'admins';public $timestamps = false;public function getJWTIdentifier(){return $this->getKey();}public function getJWTCustomClaims(){return [];}
}

database/factories/AdminFactory.php

<?phpuse Faker\Generator as Faker;$factory->define(App\Admin::class, function (Faker $faker) {return ['name' => $faker->name,'email' => $faker->unique()->safeEmail,'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret'remember_token' => str_random(10),];
});

执行 migrate:

php artisan migrate

快速创建两个用户:

factory(App\Admin::class, 2)->create();

在这里插入图片描述

创建 / 验证 Token
修改 auth 配置:

config/auth.php

'guards' => [...'admin' => ['driver' => 'jwt','provider' => 'admins',],
],
'providers' => [...'admins' => ['driver' => 'eloquent','model' => App\Models\AdminModel::class,],
],

增加了一个 admin 的 guard,同时增加了对应的 provider。

测试一下为 admin 创建 JWT。

$admin = Admin::find(2);
auth('admin')->login($admin);

在这里插入图片描述

这次我们使用了 login 方法,与 fomUser 方法一样可以为某个用户创建一个 JWT,有兴趣的同学可以看看这两个方法的区别。

接下来我们可能就需要一份同 user 一样的接口登录以及获取信息的接口:

routes/api.php

Route::post('admin/login', function (Request $request) {$credentials = $request->only('email', 'password');if (!$token = auth('admin')->attempt($credentials)) {return response()->json(['error' => 'Unauthorized'], 401);}return response()->json(['token' => $token]);
});Route::middleware('auth:admin')->get('/admin', function (Request $request) {return $request->user();
});

可以正确的创建出来 JWT:

在这里插入图片描述

也可以正确的获取到对应 admin 用户的信息。

在这里插入图片描述

容易被忽略的问题
我们先分别为 User 和 Admin 生成 JWT ,对比一下:

在这里插入图片描述

你可能会有个疑问,JWT 是通过 sub 这个字段说明模型 ID 的,也仅仅是通过这个字段去查询对应的用户,也就是说上面生成的 $userToken$adminToken 基本相同,那么是不是可以通过 $adminToken 去访问得到 User 的用户信息呢?

我们来尝试一下:

在这里插入图片描述

你会发现扩展包已经考虑到了这个问题, prv 字段用于记录扩展包的模型,相当于 $userToken 记录了 sha1('App\Models\UserModel')$adminToken 记录了 sha1('App\Models\AdminModel'),这样将不同模型的 JWT 进行隔离,不会出现问题。

需要注意的是,这个功能是在 1.0.0-rc.1 版本中才添加,对应的配置是 jwt.lock_subject默认是 true。所以之前的版本确实会出现问题,我原来是通过模型中的 getJWTCustomClaims 方法,在 JWT 中存放一些额外的标识,然后自定义中间件来验证这个标识来解决这样的问题,不过将扩展包升级到最新之后就不用担心这个问题了,我们现在是 1.0.0-rc.2 版本。

并发问题
最后我们了解一个并发问题,JWT 在刷新了之后就会被加入黑名单,这样这个 JWT 就失效了。但是客户端有时候是并发请求的,也就是多个请求使用同一个 JWT 并发的请求各自的接口,但是如果某一个请求刷新了 JWT,那么其他所有的请求都会失败。

为了解决这个问题,扩展包提供了一个机制,可以配置多长时间内,JWT 被加入黑名单之后,依然可以使用,这个机制是用来防止并发问题,所以时间并不需要太长,具体的配置是 jwt.blacklist_grace_period ,可以在 env 中配置 JWT_BLACKLIST_GRACE_PERIOD。比如我们设置为 10,加入黑名单后 10 秒内依然可用。

创建一个可以正常使用的 JWT,

在这里插入图片描述

刷新这个 JWT,再次访问用户详情接口,依然可以获取到用户信息。但是等待 10 秒之后就会报错了。

在这里插入图片描述

原文地址


http://chatgpt.dhexx.cn/article/Ku9XPGWq.shtml

相关文章

JIT是什么

什么是JIT 一些其他解释的网站&#xff1a;http://www.sohu.com/a/169704040_464084 1、动态编译&#xff08;dynamic compilation&#xff09;指的是“在运行时进行编译”&#xff1b;与之相对的是事前编译&#xff08;ahead-of-time compilation&#xff0c;简称AOT&#xf…

JWT入门教程

简介 JWT&#xff0c;JSON Web Token&#xff0c;开放的、行业标准(RFC 7519)&#xff0c;用于网络应用环境间安全传递声明。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息&#xff0c;以便于从资源服务器获取资源&#xff0c;也可以增加一些额外的…

JT项目-1

DAY01 学习京淘的意义 1 为什么选择电商项目作为java培优部分的重要项目 火(用户量广) 技术难点多,高(高并发,高可用)尤其是在中国 谷歌是全球并发最高的网站 学习成本低(无需精通业务部分) 2 学习完京淘项目对我们的就业有什么好处 代替1-2年工作经验 技术就业范…

JWT --- 入门学习

不知道为什么,不用springboot test测试或者启动类启动,会报这个错误,找不到类路径 1.常见的认证机制 basic auth &#xff1a; 每次请求都会携带用户的username&#xff0c;password&#xff0c;易被黑客拦截。 Cookie auth : 我们请求服务器&#xff0c;创建一个session对象,…

Jetty

本文介绍一个使用Jetty开发的Web的小例子。 Jetty是一个开源的servlet容器&#xff0c;它为基于Java的web容器&#xff08;例如JSP和servlet&#xff09;提供运行环境。可以把它理解为和Tomcat一样&#xff0c;不过Jetty更小更轻量级。如果想更深入学习Jetty推荐看&#xff1a…

JWT入门详解

目录 一、JWT简介 1.什么是JWT&#xff1f; 2.为什么要使用JWT&#xff1f; 二、JWT的工作原理 三、JWT的组成 1.Header&#xff08;头部&#xff09; 2.Payload(载荷) Reserved claims(保留) Public claims&#xff08;公有&#xff09; Private claims(私有) 3.s…

Ubuntu系统搭建后端Websocket服务器--基于Apache Tomcat

目录 一、概述二、基本安装2.1 Java安装2.2 Apache Tomcat安装2.3 Eclipse EE安装 三、正式部署3.1 创建一个简单java web项目3.2 服务端部署3.3 运行3.4 局域网连接Websocket 一、概述 本文针对Ubuntu系统&#xff08;Win10下的虚拟机&#xff09;进行详述&#xff0c;本文测…

部署Nginx+Tomcat+Php-fpm+mariadb主主

要求 1、前端1台Nginx&#xff0c;均衡后端2台php-fpm&#xff0c;均衡后端2台Tomcat&#xff0c;2台MYSQL采用主主架构&#xff0c;用户通过域名访问前端Nginx 域名v1.jd.com v2.jd.com访问到Discuz和Jforum不同的网站。 2、将第一道题目的部署步骤和架构图画出来。架构图上要…

【JavaWeb】WEB开发概述以及Tomcat

&#x1f50e;这里是【JavaWeb】&#xff0c;关注我学习JavaWeb不迷路 &#x1f44d;如果对你有帮助&#xff0c;给博主一个免费的点赞以示鼓励 欢迎各位&#x1f50e;点赞&#x1f44d;评论收藏⭐️ &#x1f440;专栏介绍 【JavaWeb】 目前主要更新JavaWeb&#xff0c;一起…

tomcat环境搭和管理及实现jsp通过tomcat连接mysql

25.1 什么是Tomcat 官方网站&#xff1a;http:#tomcat.apache.org/ Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持…

Tomcat的Https设置及Http自动跳转Https (Linux环境下)

1.场景还原 近期项目中要对信息传输过程中进行安全加密&#xff0c;那么第一时间浮现笔者脑海的当然是https,接下来笔者将介绍如何在web服务器Tomcat中配置Https及Http自动跳转Https 2.Https相关介绍 Https是由NetScape公司设计的一个基于Http的加密传输协议&#xff0c;可以这…

六、Tomcat集群

TOMCAT集群 目录 TOMCAT集群 1 1 集群 1 1.1 什么是集群 1 1.2 集群的特性 1 1.3 集群的分类 1 1.4 TOMCAT集群配置的优缺点 2 1.5 APACHETOMCAT 2 1.6 环境说明 2 2 软件安装 3 2.1 安装说明 3 2.2 JDK安装 3 2.3 APACHE安装 4 2.4 TOMCAT安装 4 3 集群配置 6 3.1 APACHEMOD_J…

Mycat环境搭建和管理及实现jsp通过tomcat连接mysql

一、什么是tomcat 官方网站&#xff1a;http://tomcat.apache.org/ Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持…

Liunx下Tomcat中配置SSL协议(http转https)+域名配置SSL证书

问题描述 为什么http转https?什么情况下需要用到http转https?https优点!!!https缺点!!!废话不多说了上代码,阿里的产品为例(tomcat配置ssl). 准备材料:获取到证书点击上图的帮助可查看自带的配置文档个人感觉挺详细的 配置域名SSL证书对应上图进行选择配置就ok 接下来我们就配…

Tomcat通过自带的Cluster方式实现Session会话共享

一般来说,在多个tomcat集群业务中,session会话共享是必须的需求,不然前端nginx转发过来的请求不知道之前请求在哪台tomcat节点上&#xff0c;从而就找不到session以至于最终导致请求失败。要实现tomcat session共享有多种方案,今天介绍下使用tomcat自带的cluster方式&#xff0…

redhat 7.9 部署war包(二)之 环境安装 jdk,tomcat等

tomcat服务器环境搭建 redhat 7.9系统中搭建tomcat8.5.88服务器端在redhat中安装tomcat8一.传输文件到虚拟机中二.设置系统环境变量 JAVA_HOME三.启动tomcat8 部署war包 redhat 7.9系统中搭建tomcat8.5.88服务器端 本篇文章介绍&#xff0c;如何在redhat7.9环境下安装java web…

tomcat看源码

一.环境搭建 1.官网下载tomcat9 2.idea打开 新建pom文件 <!-- pom.xml --> <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-inst…

centos 6.2 mysql和tomcat的配置_基于CentOS 6.8平台的Tomcat+MySQL+JDK环境搭建

部署环境 Server&#xff1a;CentOS 6.8 x86_64 Tomcat&#xff1a;9.0.0.M9 MySQL&#xff1a;5.7.14 JDK&#xff1a;8u102 部署准备 使用浏览器访问Apache Tomcat官网 http://tomcat.apache.org/ 下载目前最新9版本 9.0.0.M9版本tar.gz安装包 下载Apache Commons Daemon&…

Windows下配置Tomcat集群

为什么要用Tomcat集群 可以提高整体web服务器性能&#xff0c;将动态页面交给tomcat处理&#xff0c;将静态文件交给apache处理&#xff0c;可以大大提高服务器的静态文件处理性能。 可以实现web服务器的负载均衡&#xff0c;服务器可采用集群的方式来响应客户端请求。Apache的…

tomcat连接mysql及JDBC详解

一、Tomcat简介 1、Tomcat简介 Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持&#xff0c;最新的 Servlet 和JS…