Files
lgp-admin-plus-api/app/Service/wx/WxTokenService.php
LQ bcf54c2727 初始化
缺陷:主题配色需要优化整体的同风格
2026-08-14 23:21:21 +08:00

105 lines
3.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Service\wx;
use App\Models\business\WxUserModel;
use App\Service\common\UtilsService;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
/**
* 小程序用户令牌
*
* 老 lgp-wx-api 把微信的 session_key 当 token 直接返回客户端:
* 它既是解密用户数据的密钥,又永不过期,泄露等于长期冒用身份。
* 这里改成服务端自签 JWTsession_key 只留库里。
*
* payload 带 scope=wx与后台管理端的 token 互不通用——
* 否则一个小程序 token 就能打后台接口。
*/
class WxTokenService
{
private static mixed $_instance;
private const SCOPE = 'wx';
private string $secretKey;
public function __construct()
{
$secret = (string) config('nl.jwt.secret', '');
// 与后台同一个密钥但 scope 不同,验证时强制校验 scope不存在越权互通
$this->secretKey = strlen($secret) >= 32 ? $secret : hash('sha256', $secret !== '' ? $secret : 'nl_wx_jwt_fallback');
}
public static function getInstance(): null|static
{
$name = get_called_class();
if (!isset(self::$_instance[$name])) {
self::$_instance[$name] = new static();
}
return self::$_instance[$name];
}
/**
* 签发令牌
*/
public function issue(int $userId, string $appCode = ''): string
{
$now = time();
return JWT::encode([
'iat' => $now,
'exp' => $now + (int) config('nl.wx.token_ttl', 30 * 24 * 3600),
'scope' => self::SCOPE,
'uid' => $userId,
'app' => $appCode,
], $this->secretKey, 'HS256');
}
/**
* 校验令牌并返回用户;失败返回 null 由中间件统一响应
*/
public function resolveUser(?string $token): ?array
{
if (empty($token)) {
return null;
}
try {
$payload = JWT::decode($token, new Key($this->secretKey, 'HS256'));
} catch (\Throwable) {
return null;
}
if (($payload->scope ?? '') !== self::SCOPE) {
return null;
}
$userId = (int) ($payload->uid ?? 0);
if ($userId <= 0) {
return null;
}
// 每次请求回查用户:倍率、价格可见性、是否被停用都可能刚被后台改过
$user = WxUserModel::where('id', $userId)->where('deleted_at', 0)->first();
if (empty($user)) {
return null;
}
$user = $user->toArray();
unset($user['session_key']);
return $user;
}
/**
* 取当前请求的小程序用户,取不到直接中断
*/
public function requireUser(): array
{
$user = request()->attributes->get('wx_user');
if (!empty($user)) {
return $user;
}
$user = $this->resolveUser(request()->bearerToken());
if (empty($user)) {
UtilsService::getInstance()->notAuth('请先登录');
}
return $user;
}
}