Laravel 中使用 JWT 作用户登录,身份认证
什么是JWT:
JWT 全名 JSON Web Token,是一种开放标准 (RFC 7519)。
用于在网络应用环境间安全地传输信息作为 JSON 对象。
它是一种轻量级的认证和授权机制,特别适合分布式系统的身份验证。
核心特点
- 紧凑格式:体积小,可通过URL、POST参数或HTTP头发送
- 自包含:包含所有必要信息,减少数据库查询
- 可验证:使用数字签名保证完整性
- 跨语言支持:几乎所有主流编程语言都有实现
JWT 的结构
由三部分组成,用点(.)分隔:
Header.Payload.Signature
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vZGV2LXNob3AtbWFuYWdlLWFwaS5ob21lLmtsZi5jb20vc2hvcC1hcGkvbG9naW4iLCJpYXQiOjE3NDM0MTM1NjcsImV4cCI6MTc0MzQxNzE2NywibmJmIjoxNzQzNDEzNTY3LCJqdGkiOiJUZjR1OENxRHB0dW9vTHZpIiwic3ViIjoiNDgwMyIsInBydiI6IjI3ZjQxNDY0MDE3YjAwZTE5MmIxNzUyNjMzNGJlNmI1ZGIwYTBkOTQifQ.5uRxjozQ89eK-zSPLF8aV2bKxWXpsJRgR5XmU9sCy3Q
工作流程
- 用户登录:客户端发送凭据到认证服务器
- 验证凭据:服务器验证后生成JWT
- 返回JWT:服务器将JWT返回给客户端
- 存储JWT:客户端存储JWT(通常localStorage或cookie)
- 携带JWT:客户端在请求头中发送JWT
Authorization: Bearer <token>
- 验证JWT:服务器验证JWT并授权访问
laravel 安装配置JWT
1.安装JWT包
composer require tymon/jwt-auth
2.发布 JWT 配置文件
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
此时会在config 目录下生成 jwt.php
配置文件
3. 生成密钥
php artisan jwt:secret
这会在 .env
文件中添加 JWT_SECRET
,注意的是 生产环境单独生成,为了安全
用户登录配置
1.用户模型配置
创建用户模型文件,必须继承 Authenticatable
,实现 两个方法 getJWTIdentifier
,getJWTCustomClaims
,必须的。
<?phpnamespace App\Models;use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;class AdminUser extends Authenticatable implements JWTSubject
{// ... 其他代码/*** 获取JWT标识符*/public function getJWTIdentifier(){return $this->getKey();}/*** 获取JWT自定义声明*/public function getJWTCustomClaims(){return ['role' => $this->role, // 示例:添加用户角色到token// 可以添加更多自定义声明];}
}
2.配置 auth.php
文件: config/auth.php
(2.1) 配置 Guard(守卫)
Guard
是 Laravel 认证系统的核心概念之一,它定义了:
-
如何认证用户(使用什么驱动 driver)
-
session
:传统的 web 应用认证方式(使用 cookies 和 session) -
token
:API 令牌认证(Laravel 自带的基础 token 认证) -
jwt
:使用 JWT 包提供的认证驱动
-
-
从哪里获取用户信息(使用什么
provider
)- 指定使用哪个用户提供者(在 providers 数组中定义)
代码如下:
'guards' => ['web' => ['driver' => 'session','provider' => 'users',],//后台api守卫'admin-api' => ['driver' => 'jwt', // 修改为 jwt 驱动'provider' => 'admin-user', // 使用admin-user 作为 provider],],
- admin-api 是我定义的后台api的守卫
- driver驱动 设置JWT
- provider 用户提供者 用 admin-user
(2.2) 配置 providers (用户提供者)
'providers' => ['users' => ['driver' => 'eloquent','model' => App\Models\User::class,],'admin-user' => ['driver' => 'eloquent','model' => AdminUser::class,]
],
admin-user
为前面引用的用户提供者
名称- driver 为 数据驱动
eloquent
驱动(最常用),使用 Eloquent ORM 从数据库获取用户- 使用 eloquent 驱动时,模型必须实现
Authenticatable
接口,具体看第一步
- 使用 eloquent 驱动时,模型必须实现
database
驱动,直接使用数据库查询构造器(非 Eloquent)
- model 为第一步定义的用户模型 AdminUser
(2.3) 配置 默认守卫
'defaults' => ['guard' => 'admin-api','passwords' => 'users',],
passwords
配置项用于定义密码重置
功能的相关设置。此文章不细说
3.登录控制器开发
login控制器有两种验证机制:
- 手动验证登录,auth 生成token【常用】
- 自动验证登录,生成token【注意密码】
手动验证登录
// 获取用户实例
$user = User::where('mobile', $request->mobile)->first();// 手动验证密码
if (!Hash::check($request->password, $user->password)) {return response()->json(['error' => '密码错误'], 401);
}// 生成Token的三种方式(任选其一)
// 方式1:直接通过用户实例生成
$token = JWTAuth::fromUser($user); // 方式2:使用auth辅助函数
$token = auth()->login($user); // 或者自定义claims
$token = JWTAuth::claims(['user_type' => $user->type,'exp' => now()->addDays(30)->timestamp // 自定义过期时间
])->fromUser($user); // 返回带Token的响应
return response()->json(['access_token' => $token,'token_type' => 'bearer','user' => auth()->user(),
]);
上述就是登录验证 和 获取token 分离
auth
为laravel的认证系统,使用默认守卫
进行生成tokenauth()->user()
可获取到登录的用户信息
自动验证登录
// 验证输入
$validator = Validator::make($request->all(), ['mobile' => 'required|string|size:11', // 假设手机号是11位'password' => 'required|string|min:6',]);if ($validator->fails()) {return response()->json(['status' => 'error','message' => '参数验证失败','errors' => $validator->errors()], 422);}// 使用手机号作为登录凭证
$credentials = $request->only('mobile', 'password');$token = Auth::guard('admin-api')->attempt(['mobile' => $mobile, 'password' => $password, 'state' => 1]);if($token){$user = Auth::guard('admin-api')->user();return $this->success('登录成功', ['token' => $token,'user' => $user,]);}else{return $this->error('您输入的账号或密码错误', 103);}
注意
使用 attempt
方法时,需要注意你的密码是否是用 Bcrypt
算法哈希,如果不是,则会有以下报错
This password does not use the Bcrypt algorithm.
原因是 Laravel
默认认证系统 Auth
(包括 attempt
() 方法)强制要求使用 Bcrypt
算法,只有Bcrypt 算法生成的密码,才能验证通过。
通过在 Hash Facade 上调用 make 方法来哈希密码
Hash::make($request->newPassword)
小结下:
- 自动验证要求比较严格,但是也是有解决办法的。这里不过多说明,
- 正常情况下。我是手动验证。然后生成token.。
- 目前的遇到的验证,账号密码,手机号验证码等等。手动验证,灵活一点
4.前端构建请求
5.中间件补充
目录:app/Http/Middleware/UserCheckToken.php
<?phpnamespace App\Http\Middleware;use App\Http\Trait\ResponseJson;
use Closure;
use Tymon\JWTAuth\Facades\JWTAuth;class UserCheckToken
{use ResponseJson;public function handle($request, Closure $next){try{$user = auth()->user();if(!$user){return $this->error('用户未找到', 401);}}catch(\Exception $e){return $this->error('Token 验证失败', 401);}return $next($request);}}
创建中间件 UserCheckToken
auth()->user()
的作用
- 验证请求携带有效的
JWT Token
(Authorization: Bearer xxx) - JWT 会自动
解析 Token
并还原用户信息
注意:
- 同一次请求中多次调用
auth()->user()
不会重复查询数据库
,第一次查询数据库,第二次返回内存缓存
- 此
缓存
仅持续
到当前 HTTP请求结束
,下次请求
会重新解析 Token。
6. 路由配置中间件
Route::middleware([UserCheckToken::class])->group(function(){Route::get('/test', [TestController::class, 'index']);
});
将需要验证登录信息的接口,放在此中间件下即可。
上述即完整的用Jwt 实现用户的登录。里面有很多的知识点都可以进行扩展,可以实现很多强大的,自定义的需求。