TokenGuardHandler.php 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. <?php
  2. namespace Michel\Auth\Handler\Guard;
  3. use Michel\Auth\Exception\AuthenticationException;
  4. use Michel\Auth\Exception\InvalidCredentialsException;
  5. use Michel\Auth\Exception\UserNotFoundException;
  6. use Psr\Http\Message\ResponseFactoryInterface;
  7. use Psr\Http\Message\ResponseInterface;
  8. use Psr\Http\Message\ServerRequestInterface;
  9. class TokenGuardHandler implements GuardHandlerInterface
  10. {
  11. private string $apiKey;
  12. private string $headerName;
  13. /**
  14. * @var callable|null
  15. */
  16. private $onFailure;
  17. public function __construct(
  18. string $apiKey,
  19. string $headerName,
  20. callable $onFailure = null
  21. )
  22. {
  23. $this->apiKey = $apiKey;
  24. $this->headerName = $headerName;
  25. $this->onFailure = $onFailure;
  26. }
  27. /**
  28. * @throws AuthenticationException
  29. * @throws UserNotFoundException
  30. * @throws InvalidCredentialsException
  31. */
  32. public function check(ServerRequestInterface $request): void
  33. {
  34. if (empty($this->apiKey)) {
  35. throw new InvalidCredentialsException("Invalid or expired token.");
  36. }
  37. $token = $request->getHeaderLine($this->headerName);
  38. if (empty($token)) {
  39. throw new AuthenticationException("Authentication token is required.");
  40. }
  41. if (!hash_equals($this->apiKey, $token)) {
  42. throw new InvalidCredentialsException("Invalid or expired token.");
  43. }
  44. }
  45. public function onFailure(ServerRequestInterface $request, ResponseFactoryInterface $responseFactory, ?AuthenticationException $exception = null): ResponseInterface
  46. {
  47. if (!is_callable($this->onFailure)) {
  48. $status = 401;
  49. $message = $exception ? $exception->getMessage() : "Invalid API key.";
  50. $payload = [
  51. 'status' => $status,
  52. 'title' => 'Authentication Failed',
  53. 'detail' => $message,
  54. ];
  55. $response = $responseFactory->createResponse($status);
  56. $response->getBody()->write(json_encode($payload, JSON_UNESCAPED_SLASHES ));
  57. return $response
  58. ->withHeader('Content-Type', 'application/json')
  59. ->withHeader('Cache-Control', 'no-store');
  60. }
  61. return ($this->onFailure)($request, $responseFactory, $exception);
  62. }
  63. }