player_id、request->player */ class TokenMiddleware implements MiddlewareInterface { public function process(Request $request, callable $handler): Response { $token = $request->header('token'); if ($token === null || $token === '') { $auth = $request->header('authorization'); if ($auth && stripos($auth, 'Bearer ') === 0) { $token = trim(substr($auth, 7)); } } $token = $token !== null ? trim((string) $token) : ''; if ($token === '') { throw new ApiException('Please provide token', ReturnCode::UNAUTHORIZED); } try { $decoded = JwtToken::verify(1, $token); } catch (JwtTokenExpiredException $e) { throw new ApiException('Token expired, please login again', ReturnCode::TOKEN_INVALID); } catch (JwtTokenException $e) { throw new ApiException('Invalid or expired token', ReturnCode::TOKEN_INVALID); } catch (\Throwable $e) { throw new ApiException('Token format invalid', ReturnCode::TOKEN_INVALID); } $extend = $decoded['extend'] ?? []; if ((string) ($extend['plat'] ?? '') !== 'api_login') { throw new ApiException('Invalid or expired token', ReturnCode::TOKEN_INVALID); } $username = trim((string) ($extend['username'] ?? '')); if ($username === '') { throw new ApiException('Invalid or expired token', ReturnCode::TOKEN_INVALID); } $currentToken = UserCache::getSessionTokenByUsername($username); if ($currentToken === null || $currentToken === '') { $player = DicePlayer::where('username', $username)->find(); if (!$player) { throw new ApiException('Please register', ReturnCode::TOKEN_INVALID); } throw new ApiException('Please login again', ReturnCode::TOKEN_INVALID); } if ($currentToken !== $token) { throw new ApiException('Please login again (account logged in elsewhere)', ReturnCode::TOKEN_INVALID); } // 优先从 Redis 缓存取玩家,避免每次请求都查库 $player = null; $cached = UserCache::getPlayerByUsername($username); if ($cached !== null && isset($cached['id'])) { $player = (new DicePlayer())->data($cached, true); } if ($player === null) { $player = DicePlayer::where('username', $username)->find(); if (!$player) { UserCache::deleteSessionByUsername($username); throw new ApiException('Please login again', ReturnCode::TOKEN_INVALID); } UserCache::setPlayerByUsername($username, $player->hidden(['password'])->toArray()); } $request->player_id = (int) $player->id; $request->player = $player; return $handler($request); } }