/
ntcte
/
jwt-keycloak
Обзор
Документация
Войти
/
ntcte
/
jwt-keycloak
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
main
src/KeycloakJwtGuard.php
111 строк
3 KB
George Repiev
feat(guard): add stateless JWT guard for Keycloak
19 июл 2026, 12:57
19 июл 2026, 12:57
058f211
Код
Авторство
О чём код?
<?php namespace Ntcte\KeycloakAuth; use Firebase\JWT\JWK; use Firebase\JWT\JWT; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Guard; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; class KeycloakJwtGuard implements Guard { protected ?object $decodedToken = null; protected ?Authenticatable $user = null; protected bool $checked = false; public function __construct(protected Request $request) {} public function check(): bool { return $this->user() !== null; } public function guest(): bool { return ! $this->check(); } public function user(): ?Authenticatable { // если setUser() уже вызывался явно (например в тестах) — не переопределяем if ($this->user !== null) { return $this->user; } // check() и user() могут вызываться несколько раз за запрос — // декодируем токен максимум один раз if ($this->checked) { return null; } $this->checked = true; $token = $this->bearerToken(); if (! $token) { return null; } try { $jwks = $this->cachedJwks(); $decoded = JWT::decode($token, JWK::parseKeySet($jwks)); if ($decoded->iss !== config('keycloak.issuer')) { return null; } if (! in_array(config('keycloak.audience'), (array) ($decoded->aud ?? []))) { return null; } $this->decodedToken = $decoded; $this->user = new KeycloakUser($decoded); return $this->user; } catch (\Throwable $e) { report($e); return null; } } public function id(): int|string|null { return $this->user()?->getAuthIdentifier(); } public function validate(array $credentials = []): bool { return $this->check(); } public function hasUser(): bool { return $this->user() !== null; } public function setUser(Authenticatable $user): static { $this->user = $user; $this->checked = true; return $this; } protected function cachedJwks(): array { return Cache::remember( 'keycloak:jwks', now()->addSeconds(config('keycloak.jwks_cache_ttl', 3600)), fn () => Http::get(config('keycloak.jwks_uri'))->json() ); } protected function bearerToken(): ?string { return $this->request->bearerToken(); } }