Как подключить доменную авторизацию к сайту на Symfony?

Доменная авторизация (также известная как авторизация на основе домена) является одним из способов авторизации пользователей в веб-приложении на Symfony. Она позволяет ограничивать доступ к различным частям сайта на основе домена, с которого пользователь заходит.

Для подключения доменной авторизации к сайту на Symfony вам потребуется выполнить несколько шагов:

Шаг 1: Установка пакетов
Сначала необходимо установить пакет "symfony/security-bundle" и добавить его в файл "composer.json" вашего проекта. Выполните команду:

composer require symfony/security-bundle

Шаг 2: Настройка безопасности
Далее вам нужно настроить безопасность вашего приложения в файле "security.yaml". Этот файл находится в директории "config/packages". Откройте его и добавьте следующие настройки:

security:
    providers:
        domain_users:
            entity:
                class: AppEntityUser
                property: domain

    firewalls:
        domain_auth:
            pattern: ^/
            anonymous: true
            provider: domain_users
            stateless: true
            guard:
                authenticators:
                    - AppSecurityDomainAuthenticator

    access_control:
        - { path: ^/, roles: [ROLE_USER] }

В этом примере мы настроили провайдера "entity", который будет использовать сущность "User" и свойство "domain" для аутентификации пользователей. Также мы настроили брандмауэр "domain_auth", который будет использовать кастомный аутентификатор "DomainAuthenticator".

Шаг 3: Создание кастомного аутентификатора
Теперь вам нужно создать кастомный аутентификатор, который будет обрабатывать логику авторизации на основе домена. Создайте новый класс "DomainAuthenticator" в вашем проекте:

// src/Security/DomainAuthenticator.php

namespace AppSecurity;

use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreExceptionInvalidCsrfTokenException;
use SymfonyComponentSecurityCoreExceptionUsernameNotFoundException;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityGuardAbstractGuardAuthenticator;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentSecurityCsrfCsrfToken;
use SymfonyComponentSecurityCsrfCsrfTokenManagerInterface;
use SymfonyComponentSecurityCoreSecurity;
use SymfonyComponentRoutingRouterInterface;
use PsrLogLoggerInterface;

class DomainAuthenticator extends AbstractGuardAuthenticator
{
    private $csrfTokenManager;
    private $router;
    private $logger;

    public function __construct(CsrfTokenManagerInterface $csrfTokenManager, RouterInterface $router, LoggerInterface $logger)
    {
        $this->csrfTokenManager = $csrfTokenManager;
        $this->router = $router;
        $this->logger = $logger;
    }

    public function supports(Request $request)
    {
        return true;
    }

    public function getCredentials(Request $request)
    {
        return [
            'token' => $request->headers->get('X-AUTH-TOKEN'),
        ];
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        if (null === $credentials['token']) {
            return;
        }

        try {
            return $userProvider->loadUserByUsername($credentials['token']);
        } catch (UsernameNotFoundException $e) {
            throw new InvalidCsrfTokenException('Invalid CSRF token');
        }
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        $valid = // валидация токена

        if (!valid) {
            throw new InvalidCsrfTokenException('Invalid CSRF token');
        }

        return true;
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        return null;
    }

    public function onAuthenticationFailure(Request $request, SymfonyComponentSecurityCoreExceptionAuthenticationException $exception)
    {
        return new Response('Could not authenticate', 403);
    }

    public function start(Request $request, SymfonyComponentSecurityCoreExceptionAuthenticationException $authException = null)
    {
        $url = $this->router->generate('domain_login');

        return new RedirectResponse($url);
    }

    public function supportsRememberMe()
    {
        return false;
    }
}

В этом примере мы создали кастомный аутентификатор, который будет проверять токен авторизации, переданный в заголовке "X-AUTH-TOKEN". Вы можете настроить кастомную логику проверки токена в методе "checkCredentials".

Шаг 4: Создание роутинга и контроллера
Наконец, создайте маршрут и контроллер для страницы логина пользователя по домену. Например, в файле "config/routes.yaml" добавьте следующий маршрут:

domain_login:
  path: /login
  controller: AppControllerLoginController::login

Затем создайте контроллер "LoginController" и добавьте в него метод "login", который будет отображать страницу логина по домену:

// src/Controller/LoginController.php

namespace AppController;

use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAnnotationRoute;

class LoginController
{
    /**
     * @Route("/login", name="domain_login")
     */
    public function login()
    {
        return new Response('Domain login page');
    }
}

Теперь, когда вы настроили доменную авторизацию, вы можете использовать ее в своем приложении Symfony. Пользователи смогут получить доступ к различным частям сайта, основываясь на домене, с которого они заходят.