Как реализовать аутентификацию в Symfony?php-78

1. Установка компонентов безопасности

Сначала установите необходимые компоненты:

composer require symfony/security-bundle symfony/maker-bundle

2. Настройка security.yaml

Основная конфигурация в config/packages/security.yaml:

security:
    enable_authenticator_manager: true
    password_hashers:
        App\Entity\User: 'auto'

    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

    firewalls:
        main:
            lazy: true
            provider: app_user_provider
            form_login:
                login_path: app_login
                check_path: app_login
            logout:
                path: app_logout

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }
        - { path: ^/login, roles: PUBLIC_ACCESS }

3. Создание сущности User

Генерация сущности пользователя:

php bin/console make:user

Пример получившейся сущности:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;

#[ORM\Entity(repositoryClass: UserRepository::class)]
class User implements UserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 180, unique: true)]
    private string $email;

    #[ORM\Column]
    private array $roles = [];

    #[ORM\Column]
    private string $password;

    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';
        return array_unique($roles);
    }

    public function eraseCredentials() {}
    public function getUserIdentifier(): string { return $this->email; }
}

4. Создание формы входа

Генерация контроллера аутентификации:

php bin/console make:auth

Пример контроллера:

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class SecurityController extends AbstractController
{
    #[Route('/login', name: 'app_login')]
    public function login(AuthenticationUtils $authenticationUtils): Response
    {
        $error = $authenticationUtils->getLastAuthenticationError();
        $lastUsername = $authenticationUtils->getLastUsername();

        return $this->render('security/login.html.twig', [
            'last_username' => $lastUsername,
            'error' => $error
        ]);
    }

    #[Route('/logout', name: 'app_logout')]
    public function logout(): void {}
}

5. Шаблон login.html.twig

{% extends 'base.html.twig' %}

{% block body %}
    {% if error %}
        <div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
    {% endif %}

    <form method="post">
        <input type="email" name="_username" value="{{ last_username }}" required>
        <input type="password" name="_password" required>
        <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
        <button type="submit">Login</button>
    </form>
{% endblock %}

6. Регистрация пользователей

Создаем форму регистрации:

php bin/console make:registration-form

Пример обработчика:

namespace App\Controller;

use App\Entity\User;
use App\Form\RegistrationFormType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class RegistrationController extends AbstractController
{
    #[Route('/register', name: 'app_register')]
    public function register(
        Request $request,
        UserPasswordHasherInterface $passwordHasher,
        EntityManagerInterface $entityManager
    ): Response {
        $user = new User();
        $form = $this->createForm(RegistrationFormType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $user->setPassword(
                $passwordHasher->hashPassword(
                    $user,
                    $form->get('plainPassword')->getData()
                )
            );

            $entityManager->persist($user);
            $entityManager->flush();

            return $this->redirectToRoute('app_home');
        }

        return $this->render('registration/register.html.twig', [
            'registrationForm' => $form->createView(),
        ]);
    }
}

7. JWT аутентификация

Установка компонентов:

composer require lexik/jwt-authentication-bundle

Генерация ключей:

mkdir -p config/jwt
openssl genpkey -out config/jwt/private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
openssl pkey -in config/jwt/private.pem -out config/jwt/public.pem -pubout

Настройка security.yaml для API:

firewalls:
    api:
        pattern: ^/api
        stateless: true
        jwt: ```

access_control:
    - { path: ^/api/login, roles: PUBLIC_ACCESS }
    - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

8. Проверка аутентификации в контроллерах

Пример защищенного роута:

#[Route('/profile', name: 'app_profile')]
public function profile(): Response
{
    $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');

    $user = $this->getUser();
    return $this->render('profile/index.html.twig');
}

Резюмируем:

  1. Основные компоненты:

    • security.yaml - центральная конфигурация
    • Сущность User - реализует UserInterface
    • Провайдеры пользователей - загрузка пользователей
  2. Способы аутентификации:

    • Форма входа (form_login)
    • JSON Web Tokens (JWT)
    • HTTP Basic
    • Кастомные аутентификаторы
  3. Ключевые моменты:

    • Всегда используйте хеширование паролей
    • Реализуйте CSRF защиту для форм
    • Разделяйте роли и права доступа
    • Для API используйте stateless аутентификацию

Для production-окружения дополнительно:

  • Настройте сброс пароля
  • Реализуйте верификацию email
  • Добавьте двухфакторную аутентификацию
  • Настройте политики паролей