#php #symfony #security #yaml #symfony5
Вопрос:
Я просто обновляю свое приложение symfony 4.4 до 5.3, чтобы использовать некоторые новые интересные вещи (UX, UUID,..). Поэтому я запустил новый проект и запустил make:auth
команду, чтобы создать компоненты безопасности по последним значениям по умолчанию. Все работает идеально, за исключением функции «Запомни меня». Файл cookie просто не установлен (независимо от того, в каком браузере). Может быть, вы сможете мне помочь
безопасность.yaml
security:
enable_authenticator_manager: true
password_hashers:
AppEntityUser:
algorithm: auto
providers:
app_user_provider:
entity:
class: AppEntityUser
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
custom_authenticator: AppSecurityLoginFormAuthenticator
pattern: ^/
logout:
path: _logout
target: _index
remember_me:
secret: '%env(APP_SECRET)%'
lifetime: 31536000 # 1 year in seconds
always_remember_me: true
path: _index
switch_user: true
role_hierarchy:
ROLE_USER: ROLE_USER
ROLE_ADMIN: [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]
access_control:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/reset-password, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/datenschutz, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/impressum, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/worker, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/, role: ROLE_USER }
Логинформ-аутентификатор
<?php
namespace AppSecurity;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingGeneratorUrlGeneratorInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreSecurity;
use SymfonyComponentSecurityHttpAuthenticatorAbstractLoginFormAuthenticator;
use SymfonyComponentSecurityHttpAuthenticatorPassportBadgeCsrfTokenBadge;
use SymfonyComponentSecurityHttpAuthenticatorPassportBadgeUserBadge;
use SymfonyComponentSecurityHttpAuthenticatorPassportCredentialsPasswordCredentials;
use SymfonyComponentSecurityHttpAuthenticatorPassportPassport;
use SymfonyComponentSecurityHttpAuthenticatorPassportPassportInterface;
use SymfonyComponentSecurityHttpUtilTargetPathTrait;
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = '_login';
private UrlGeneratorInterface $urlGenerator;
public function __construct(UrlGeneratorInterface $urlGenerator)
{
$this->urlGenerator = $urlGenerator;
}
public function authenticate(Request $request): PassportInterface
{
$email = $request->request->get('email', '');
$request->getSession()->set(Security::LAST_USERNAME, $email);
return new Passport(
new UserBadge($email),
new PasswordCredentials($request->request->get('password', '')),
[
new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('_index'));
}
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
public function supportsRememberMe(): bool
{
return true;
}
}
логин.html.веточка
{% extends 'base.html.twig' %}
{% block title %}{{ ('meta.title.login')|trans }}{% endblock %}
{% block body %}
<h1>{{ ('security.login.header')|trans }}</h1>
<form method="post">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<div class="mb-3">
<label for="inputEmail" class="form-label">{{ ('security.login.email')|trans }}</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" autocomplete="email" required autofocus>
</div>
<div class="mb-3">
<label for="inputPassword" class="form-label">{{ ('security.login.password')|trans }}</label>
<input type="password" name="password" id="inputPassword" class="form-control" autocomplete="current-password" required>
</div>
<div class="mb-3">
<a href="{{ path('app_forgot_password_request') }}">
{{ ('button.forgot_password')|trans }}
</a>
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<button class="btn btn-lg btn-outline-success" type="submit">
{{ ('security.login.button')|trans }}
</button>
</form>
{% endblock %}
Заранее большое спасибо!!
————— РЕДАКТИРОВАТЬ ———————-
Первоначально я задавал этот вопрос для версии 5.4, но он также актуален и для версии 5.3 — я попробовал и то, и другое, не установив файл cookie
Комментарии:
1. 5.4 еще не выпущен.
2. То же самое поведение для версии 5.3, которая выпущена
3.
path
Не должен быть фактический путь, а не название пути?4. Честно говоря, это не имеет никакого эффекта. Я могу оставить его пустым для значения по умолчанию или ввести / или что-нибудь еще
5. Конфигурация выглядит нормально. Используйте сетевые инструменты вашего браузера, чтобы убедиться, что файл cookie REMEMBERME отправляется должным образом.
Ответ №1:
Я настроил тестовое приложение и подтвердил, что файл cookie «Запомни меня» не отправлялся, но затем я обманул и увидел подсказку на канале Symfony Slack. При использовании новой системы аутентификации на основе паспорта вам нужно использовать значок «Запомни меня». Это задокументировано здесь.
Поэтому обновите свой аутентификатор::аутентифицируйте метод с помощью:
return new Passport(
new UserBadge($email),
new PasswordCredentials($request->request->get('password', '')),
[
new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
new RememberMeBadge(),
]
);
Все это, казалось, работало на меня.
Комментарии:
1. Это правда, я только что добавил этот значок, и теперь он работает и на меня
Ответ №2:
У меня была та же проблема, файл cookie REMEMBER был установлен, но не вызывался при удалении PHPSESSID . Потратив время, я нашел в своем классе пользовательских сущностей это (я добавил после обновления Symfony, не задумываясь об этом). :
public function getUserIdentifier() {
return $this->id;
}
Но в securiy.yml мой провайдер пользователей является :
app_user_provider:
entity:
class: AppEntityUser
property: email
Поэтому я изменил свою функцию getUserIdentifier на эту, и теперь она работает :
public function getUserIdentifier() {
return $this->email;
}
Комментарии:
1. Не работает в Symfony >=5.3.