You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
3.0 KiB
PHP

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Services;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Illuminate\Support\Carbon;
use InvalidArgumentException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
class JwtService
{
/**
* 生成访问令牌
* @param array $payload 自定义载荷如用户ID、角色
* @return string
*/
public function generateToken(array $payload): string
{
$secret = config('app.jwt.secret');
$algorithm = config('app.jwt.algorithm');
$expiresAt = Carbon::now()->addSeconds(config('app.jwt.expire'))->timestamp;
// 标准JWT载荷 + 自定义载荷
$jwtPayload = array_merge([
'iss' => config('app.url'), // 签发者
'iat' => Carbon::now()->timestamp, // 签发时间
'exp' => $expiresAt, // 过期时间
'nbf' => Carbon::now()->timestamp, // 生效时间
], $payload);
return JWT::encode($jwtPayload, $secret, $algorithm);
}
/**
* 生成刷新令牌
* @param int $userId 用户ID
* @return string
*/
public function generateRefreshToken(int $userId): string
{
$secret = config('app.jwt.secret');
$algorithm = config('app.jwt.algorithm');
$expiresAt = Carbon::now()->addSeconds(config('app.jwt.refresh_expire'))->timestamp;
$refreshPayload = [
'iss' => config('app.url'),
'iat' => Carbon::now()->timestamp,
'exp' => $expiresAt,
'sub' => 'refresh_token', // 标识为刷新令牌
'user_id' => $userId,
];
return JWT::encode($refreshPayload, $secret, $algorithm);
}
/**
* 验证并解析JWT令牌
* @param string $token
* @return array 解析后的载荷
* @throws ExpiredException|SignatureInvalidException|InvalidArgumentException
*/
public function verifyToken(string $token): array
{
$secret = config('app.jwt.secret');
$algorithm = config('app.jwt.algorithm');
try {
// 验证并解析令牌
$decoded = JWT::decode($token, new Key($secret, $algorithm));
return (array) $decoded;
} catch (ExpiredException $e) {
throw new ExpiredException('Token已过期', 401);
} catch (SignatureInvalidException $e) {
throw new SignatureInvalidException('Token签名无效', 400);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException('Token格式错误', 400);
}
}
/**
* 解析令牌(不验证签名/过期,仅用于读取载荷)
* @param string $token
* @return array
*/
public function decodeTokenWithoutVerify(string $token): array
{
$parts = explode('.', $token);
if (count($parts) !== 3) {
throw new InvalidArgumentException('Token格式错误');
}
$payload = json_decode(base64_decode($parts[1]), true);
return $payload ?: [];
}
}