resolveBySiteCode((string) $player->site_code); } public function resolveBySiteCode(string $siteCode): PartnerSiteConfig { $siteCode = trim($siteCode); if ($siteCode === '') { return $this->legacyFallbackConfig($siteCode); } $cacheKey = self::CACHE_PREFIX.$siteCode; /** @var array $cached */ $cached = Cache::remember($cacheKey, self::CACHE_TTL_SECONDS, function () use ($siteCode): array { $site = AdminSite::query()->where('code', $siteCode)->first(); $config = $site !== null ? $this->fromAdminSite($site) : $this->legacyFallbackConfig($siteCode); return $config->toCacheArray(); }); return PartnerSiteConfig::fromCacheArray($cached); } public function forgetCache(string $siteCode): void { Cache::forget(self::CACHE_PREFIX.trim($siteCode)); } /** * 从未验签的 JWT 中读取 site_code(仅用于选取验签密钥)。 */ public function peekSiteCodeFromJwt(string $jwt): ?string { $jwt = trim($jwt); $parts = explode('.', $jwt); if (count($parts) !== 3) { return null; } $payloadJson = $this->base64UrlDecode($parts[1]); if ($payloadJson === null) { return null; } $payload = json_decode($payloadJson, true); if (! is_array($payload)) { return null; } $siteKey = (string) config('lottery.player_auth.jwt.claim_site_code', 'site_code'); $siteCode = $payload[$siteKey] ?? null; return is_string($siteCode) && $siteCode !== '' ? $siteCode : null; } private function fromAdminSite(AdminSite $site): PartnerSiteConfig { return new PartnerSiteConfig( siteCode: (string) $site->code, enabled: $site->isEnabled(), walletApiUrl: is_string($site->wallet_api_url) && $site->wallet_api_url !== '' ? rtrim($site->wallet_api_url, '/') : null, walletDebitPath: (string) ($site->wallet_debit_path ?: '/wallet/debit-for-lottery'), walletCreditPath: (string) ($site->wallet_credit_path ?: '/wallet/credit-from-lottery'), walletBalancePath: (string) ($site->wallet_balance_path ?: '/wallet/balance'), ssoJwtSecret: $site->decryptedSsoJwtSecret(), walletApiKey: $site->decryptedWalletApiKey(), walletTimeoutSeconds: max(1, (int) ($site->wallet_timeout_seconds ?? 10)), source: PartnerSiteConfig::SOURCE_DATABASE, ); } private function legacyFallbackConfig(string $siteCode): PartnerSiteConfig { $defaultCode = (string) config('lottery.integration.default_site_code', 'default_site'); $legacyCodes = array_filter([ $defaultCode, (string) config('lottery.integration.legacy_env_site_code', ''), ]); $sso = config('lottery.main_site.sso_jwt_secret'); $walletUrl = config('lottery.main_site.wallet_api_url'); $walletKey = config('lottery.main_site.wallet_api_key'); $hasLegacy = (is_string($sso) && $sso !== '') || (is_string($walletUrl) && trim((string) $walletUrl) !== ''); if ($hasLegacy && ( $siteCode === '' || in_array($siteCode, $legacyCodes, true) || app()->environment(['local', 'testing']) )) { if ($siteCode !== '') { Log::warning('partner_site_config.legacy_env_fallback', [ 'site_code' => $siteCode, 'hint' => 'Configure admin_sites row for this site_code', ]); } return new PartnerSiteConfig( siteCode: $siteCode !== '' ? $siteCode : $defaultCode, enabled: true, walletApiUrl: is_string($walletUrl) && trim($walletUrl) !== '' ? rtrim(trim($walletUrl), '/') : null, walletDebitPath: (string) config('lottery.main_site.wallet_debit_path', '/wallet/debit-for-lottery'), walletCreditPath: (string) config('lottery.main_site.wallet_credit_path', '/wallet/credit-from-lottery'), walletBalancePath: (string) config('lottery.main_site.wallet_balance_path', '/wallet/balance'), ssoJwtSecret: is_string($sso) && $sso !== '' ? $sso : null, walletApiKey: is_string($walletKey) && $walletKey !== '' ? $walletKey : null, walletTimeoutSeconds: max(1, (int) config('lottery.main_site.wallet_timeout', 10)), source: PartnerSiteConfig::SOURCE_LEGACY_ENV, ); } return new PartnerSiteConfig( siteCode: $siteCode, enabled: false, walletApiUrl: null, walletDebitPath: '/wallet/debit-for-lottery', walletCreditPath: '/wallet/credit-from-lottery', walletBalancePath: '/wallet/balance', ssoJwtSecret: null, walletApiKey: null, walletTimeoutSeconds: 10, source: PartnerSiteConfig::SOURCE_DATABASE, ); } private function base64UrlDecode(string $segment): ?string { $remainder = strlen($segment) % 4; if ($remainder > 0) { $segment .= str_repeat('=', 4 - $remainder); } $decoded = base64_decode(strtr($segment, '-_', '+/'), true); return $decoded === false ? null : $decoded; } }