环境:php8.3\tp8.1\firebase-jwt6.1
app\middleware\JwtAuth
php
<?php
namespace app\middleware;
use app\common\library\JwtHandler;
use think\Request;
use think\facade\Env;
class JwtAuth
{
public function handle(Request $request, \Closure $next)
{
// 获取当前请求路径
$path = $request->pathinfo();
// 如果是登录或注册接口,跳过 Token 校验
if (in_array($path, ['api/auth/login/', 'api/auth/register/'])) {
return $next($request);
}
// 获取 Authorization 头
$token = $request->header('Authorization');
if (!$token) {
$this->handleTokenError('Token not provided');
}
// 如果 Authorization 头中有 Bearer token,处理它
if (str_starts_with($token, 'Bearer ')) {
$token = substr($token, 7); // 去掉 'Bearer ' 前缀
}
try {
// 解码并验证 Token
$data = JwtHandler::getData($token);
if (!$data) {
$this->handleTokenError('Invalid or expired token');
}
// 将解码的用户数据附加到请求对象
$request->user = $data;
} catch (\Exception $e) {
$this->handleTokenError('Invalid or expired token');
}
return $next($request);
}
// 处理 Token 错误的公共方法
private function handleTokenError($message): void
{
// 在生产环境中提供简洁的错误信息
if (Env::get('app.env') === 'production') {
json([
'code' => 401,
'message' => 'Invalid or expired token'
]);
return;
}
// 在开发环境中提供详细的错误信息
json([
'code' => 401,
'message' => $message
]);
}
}
app\common\library\JwtHandler;
php
<?php
namespace app\common\library;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use think\exception\ValidateException;
class JwtHandler
{
private static string $key = 'quwei'; // 密钥
/**
* 生成JWT
* @param array $payload
* @return string
* @throws ValidateException
*/
public static function encode(array $payload): string
{
$issuedAt = time(); // 当前时间
$expirationTime = $issuedAt + 60; // 设置过期时间为1小时
$payload['iat'] = $issuedAt; // 签发时间
$payload['exp'] = $expirationTime; // 过期时间
try {
// 生成JWT
return JWT::encode($payload, self::$key, 'HS256');
} catch (\UnexpectedValueException $e) {
throw new ValidateException('Error encoding JWT: ' . $e->getMessage());
}
}
/**
* 解码JWT
* @param string $jwt
* @return object|null
* @throws ValidateException
*/
public static function decode(string $jwt): ?object
{
try {
// 解码JWT
return JWT::decode($jwt, new Key(self::$key, 'HS256'));
} catch (\Firebase\JWT\ExpiredException $e) {
throw new ValidateException('Token expired: ' . $e->getMessage());
} catch (\UnexpectedValueException $e) {
throw new ValidateException('Invalid token: ' . $e->getMessage());
} catch (\Exception $e) {
throw new ValidateException('Error decoding JWT: ' . $e->getMessage());
}
}
/**
* 获取JWT中的数据
* @param string $jwt
* @return array|null
*/
public static function getData(string $jwt): ?array
{
try {
$decoded = self::decode($jwt);
return $decoded ? (array)$decoded : null;
} catch (ValidateException $e) {
return null; // 解码失败时返回 null
}
}
}
app\api\controller\auth.php
php
<?php
namespace app\api\controller;
use app\BaseController;
use app\common\library\JwtHandler;
use think\Request;
use think\response\Json;
class Auth extends BaseController
{
/**
* 用户登录,生成JWT
* @param Request $request
* @return Json
*/
public function login(Request $request): Json
{
$username = $request->post('username');
$password = $request->post('password');
// 假设你通过用户名和密码来验证用户
if ($username === 'John' && $password === '123') {
// 生成 JWT,payload 可以根据需要调整
$payload = [
'sub' => 1, // 用户ID
'name' => $username,
'role' => 'admin'
];
// 生成JWT
$jwt = JwtHandler::encode($payload);
return json(['code' => 200, 'message' => 'Login successful', 'token' => $jwt]);
}
return json(['code' => 400, 'message' => 'Invalid credentials'], 400);
}
/**
* 验证JWT,获取用户信息
* @param Request $request
* @return Json
*/
public function me(Request $request): Json
{
$token = $request->header('Authorization'); // 获取Authorization头中的Token
if (!$token) {
return json(['code' => 401, 'message' => 'Token not provided'], 401);
}
// 解码Token
try {
$data = JwtHandler::getData($token);
if ($data) {
return json(['code' => 200, 'message' => 'Success', 'data' => $data]);
}
return json(['code' => 401, 'message' => 'Invalid or expired token'], 401);
} catch (\Exception $e) {
return json(['code' => 401, 'message' => 'Invalid or expired token'], 401);
}
}
public function getUserProfile(Request $request): Json
{
// 直接访问解码后的用户信息
$user = $request->user;
// 返回当前用户的个人资料
return json(['code' => 200, 'data' => $user]);
}
}
这是完整的步骤,欢迎大家指正。