深入了解jwt-auth:基于JSON Web Token的用户认证机制及其工作原理
JWT-auth 即 JSON Web Token Authentication,它是以 JSON Web Token(JWT)为基础的用户认证机制。这是一个较为流行的身份验证方案,在用户登录后会生成令牌(Token),然后在每次请求时都传递该令牌,以此来验证用户的身份。

下面是 jwt-auth 的工作原理:
用户进行登录时需提供有效的凭证,像用户名和密码等,以此发起登录请求。服务器会对用户的凭证进行验证,接着为用户生成一个基于 JWT 的 Token。之后,服务器把生成的 Token 返还给客户端,使其作为身份验证的凭证。客户端发送 Token:在每一次发起请求的时候,客户端会把 Token 当作 Authorization 头的一部分,亦或是作为请求参数的一部分,然后发送给服务器。服务器接收到请求后,会对收到的 Token 进行有效性和合法性的验证。如果 Token 是有效的且合法的,服务器会利用其中的信息来鉴定用户的身份,并且会根据需要授权用户去访问相应的资源。如果用户通过了身份验证以及授权,服务器就会处理请求并返回相应的数据。
JWT Token 的结构通常包含三部分。其中,Header 包含了 Token 的类型以及算法等信息。Payload 则包含了 Token 的声明以及自定义的附加信息。而 Signature 是对前两部分数据进行的签名,它的作用是用于验证 Token 的完整性以及进行身份验证。
在 Laravel 框架里,我们能够利用 jwt-auth 扩展包轻松达成用户 Token 登录验证的功能。jwt-auth 给予了简单且便于使用的接口以及功能,有助于我们生成并验证运用 JWT 的用户令牌。
步骤一:安装和配置 jwt-auth
首先,我们得在 Laravel 项目里安装 jwt-auth 这个扩展包。接着打开终端,进到项目的根目录当中,然后执行如下这些命令:
需要使用 tymon/jwt-auth 这个包,通过 composer 命令来进行安装。即执行 composer require tymon/jwt-auth 这一操作,以引入该包到项目中。
安装完毕后,我们得进行一系列的配置操作。其一,运行以下这些命令来发布 jwt-auth 的核心配置文件以及数据库迁移文件。
使用 php artisan 执行 vendor:publish 命令,指定提供程序为 "Tymon\JWTAuth\Providers\LaravelServiceProvider"
接下来,生成 jwt-auth 的秘钥:
php artisan jwt:secret
这将会生成一个随机字符串,并自动将其添加到.env文件中。
步骤二:配置用户模型和认证逻辑
在开始使用 jwt-auth 扩展包之前,我们得配置相关的用户模型。同时,我们也需要配置相关的认证逻辑。
首先,我们来创建一个 User 模型,接着执行与之相应的数据库迁移。能够使用如下命令来生成用户模型和迁移文件:
使用 php artisan 命令来创建一个名为 User 的模型,并同时生成迁移文件。
执行完毕后,你能够在 app 目录下找到 User 模型文件。同时,你还能在 database/migrations 目录中找到生成的用户迁移文件。倘若你已经拥有 user 模型,那么就可以跳过上述步骤。
接下来,我们要打开 User 模型文件。并且,需要去实现 Tymon\JWTAuth\Contracts\JWTSubject 接口里的两个方法,分别是 getJWTIdentifier 和 getJWTCustomClaims。
'datetime',
];
// 声明 JWTSubject 接口必须实现的方法
获取 JWT 标识符的公共函数。
{
return $this->getKey();
}
获取 JWT 自定义声明的公共函数。这个函数用于获取与 JWT 相关的自定义声明。它在处理 JWT 相关的操作时起到关键作用,能够获取特定的自定义信息并返回给调用者。
{
return [];
}
}
在 getJWTIdentifier 这个方法里,我们会返回用户的唯一标识,一般来讲是用户的 ID。而在 getJWTCustomClaims 这个方法中,我们能够返回其他一些自定义的声明。
首先打开 config/auth.php 配置文件。然后确认 guards 中的 api 驱动是使用 jwt-auth 驱动。如此一来,Laravel 就会使用 jwt-auth 来进行用户认证。
'guards' => [
// ...
'api' => [
将“driver”替换为“jwt”。
“provider”被替换为“users”。
],
],
步骤三:实现用户登录验证
现在,我们可以开始实现用户 Token 登录验证的功能了。
首先,创建一个新的控制器,用于处理用户登录逻辑:
使用 php artisan 命令来创建一个名为 AuthController 的控制器。
打开 AuthController 文件后,我们能够在其中添加一个 login 方法。这个方法的作用是验证用户的身份信息,并且会生成并返回 JWT Token。
使用 Illuminate\Support\Facades\Auth 这个类库。
调用 Tymon\JWTAuth\Facades\JWTAuth 这个类。
此函数名为 login,它接收一个参数 $code,用于执行登录相关的操作。函数内部会根据传入的 $code 进行一系列的处理和验证,以完成登录过程。
try {
// 获取第三方登录后的 unionid
$login 等于 WechatApi 获取平台的操作结果,这个操作的参数是 $code 。
if (!$login) {
抛出一个异常,异常信息为“获取用户信息失败”。
}
// 查找或创建对应的用户
使用 where 方法,指定条件为 'unionid' 等于 $login['unionid'],然后通过 first 方法获取第一个匹配的结果,并将其赋值给 $user 变量。
if (!$user) {
$user = new User();
$user 的 unionid 等于登录信息中的 unionid 。
$user 的昵称等于“用户”加上一个 1000 到 9999 之间的随机数;$user 的昵称由“用户”和一个 1000 到 9999 之间的随机数组成;$user 的昵称是“用户”与一个 1000 到 9999 之间的随机数的组合;$user 的昵称等于先写“用户”再加上一个 1000 到 9999 之间的随机数;“用户”加上一个 1000 到 9999 之间的随机数就得到了 $user 的昵称;$user 的昵称是在“用户”后面加上一个 1000 到 9999 之间的随机数所形成的。
$user->save();
平台通过创建[UserPlatforms::create([ 这个操作来生成相关内容,具体来说就是创建了[UserPlatforms::create([ 所涉及的相关平台相关的内容,这些平台是通过[UserPlatforms::create([ 这个过程来创建和确定的。
$user 的 id 被赋值给了 'user_id'
'platform_type' => 1,
'platform_identifier' 等于 $login['openid'] ;
'access_token' 等于 $login 中的 'access_token' 。
'expires_at' => 日期('Y-m-d H:i:s', 时间() + 6000)
]);
}
// 使用 Auth::login() 方法手动登录用户
Auth::login($user);
// 生成并返回 JWT Token
JWTAuth 通过从已认证的用户(Auth::user())中获取信息来生成 $token 。
$user->token = $token;
return $user;
} catch (Exception $e) {
抛出一个新的异常,异常的消息为 $e 的消息,异常的代码为 $e 的代码。
}
}
在上述代码里,我们第一步是通过特定方法去查找或者创建与之对应的用户记录。接着,运用 Auth::login()这个方法来手动让用户登录,并且把用户的信息存储到当前的会话当中。
首先,使用 JWTAuth::fromUser()方法来为登录的用户进行操作。接着,通过该方法为登录用户生成 JWT。最后,把生成的 Token 返还给前端。
前端收到 Token 后,能够把它存储在客户端里,像 LocalStorage 或者 Cookie 这类地方。并且在后续的请求过程中,会把它当作授权凭证来进行身份验证。
创建一个新的中间件,比如 AuthenticateUser。这个中间件的作用是验证用户是否已经登录,同时检查用户的身份认证信息是否有效。
在终端中运行以下命令创建新的中间件:
使用 php artisan 命令创建中间件 AuthenticateUser 。
然后,在生成的中间件类中,可以这样编写逻辑来验证用户身份:
通过 Token 来获取用户信息并进行身份验证。
if ($user) {
// 将 $user 存储到请求的属性中
$request 的 attributes 设置了名为 'user' 的值为 $user 。
return $next($request);
} else {
ApiResponse 返回了一个错误,错误信息为“用户不存在请重新登录”,错误代码为 ApiResponse::TOKEN_INVALID_CODE。
}
如果捕获到 TokenInvalidException 异常,那么就会执行以下操作。
把 TokenInvalidException 异常再次抛出出去。
使用“token 已失效或存在错误”作为返回的错误信息,并将错误代码设置为 ApiResponse 的 TOKEN_INVALID_CODE。即返回一个 ApiResponse 对象,其中包含错误信息“token 已失效或存在错误”和错误代码 ApiResponse::TOKEN_INVALID_CODE。
} catch (Exception $e) {
// 处理其他异常情况
返回 ApiResponse 的错误,错误信息为“验证令牌错误”,错误代码为 ApiResponse 的 TOKEN_INVALID_CODE。
}
}
}