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

122 lines
3.0KB

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Services;
  4. use Core\Response;
  5. use Stevenmaguire\OAuth2\Client\Provider\Keycloak;
  6. class AuthService
  7. {
  8. private static function config(): array
  9. {
  10. static $config = null;
  11. if ($config === null) {
  12. $config = require __DIR__ . '/../../config/auth.php';
  13. }
  14. return $config['keycloak'];
  15. }
  16. public static function provider(): Keycloak
  17. {
  18. $cfg = self::config();
  19. return new Keycloak([
  20. 'authServerUrl' => rtrim($cfg['base_url'], '/'),
  21. 'realm' => $cfg['realm'],
  22. 'clientId' => $cfg['client_id'],
  23. 'clientSecret' => $cfg['client_secret'],
  24. 'redirectUri' => $cfg['redirect_uri'],
  25. ]);
  26. }
  27. /**
  28. * Decode user claims from the access token JWT payload.
  29. * Avoids calling the userinfo endpoint, which Keycloak may return as a
  30. * signed JWT (application/jwt) rather than JSON — causing decryption errors.
  31. *
  32. * @return array<string, mixed>
  33. */
  34. public static function claimsFromToken(string $jwt): array
  35. {
  36. $parts = explode('.', $jwt);
  37. if (count($parts) < 2) {
  38. return [];
  39. }
  40. $payload = base64_decode(strtr($parts[1], '-_', '+/'), true);
  41. if ($payload === false) {
  42. return [];
  43. }
  44. $data = json_decode($payload, true);
  45. return is_array($data) ? $data : [];
  46. }
  47. public static function requireLogin(): ?Response
  48. {
  49. if (!self::isLoggedIn()) {
  50. $_SESSION['auth_return_to'] = $_SERVER['REQUEST_URI'] ?? '/';
  51. return Response::redirect('/auth/login');
  52. }
  53. return null;
  54. }
  55. public static function isLoggedIn(): bool
  56. {
  57. return !empty($_SESSION['auth_user']);
  58. }
  59. public static function getCurrentUser(): array
  60. {
  61. return $_SESSION['auth_user'] ?? [];
  62. }
  63. public static function getCurrentUsername(): string
  64. {
  65. $user = self::getCurrentUser();
  66. return $user['preferred_username'] ?? $user['email'] ?? '';
  67. }
  68. public static function storeUser(array $userInfo): void
  69. {
  70. $_SESSION['auth_user'] = $userInfo;
  71. }
  72. public static function clearSession(): void
  73. {
  74. $_SESSION = [];
  75. if (ini_get('session.use_cookies')) {
  76. $params = session_get_cookie_params();
  77. setcookie(
  78. session_name(),
  79. '',
  80. time() - 42000,
  81. $params['path'],
  82. $params['domain'],
  83. $params['secure'],
  84. $params['httponly']
  85. );
  86. }
  87. session_destroy();
  88. }
  89. public static function logoutUrl(): string
  90. {
  91. $cfg = self::config();
  92. $base = rtrim($cfg['base_url'], '/');
  93. $realm = $cfg['realm'];
  94. $postLogout = urlencode($cfg['post_logout_redirect_uri']);
  95. return "{$base}/realms/{$realm}/protocol/openid-connect/logout?redirect_uri={$postLogout}";
  96. }
  97. }

Powered by TurnKey Linux.