#symfony #symfony4 #symfony-4.2
#symfony #symfony4 #symfony-4.2
Вопрос:
Я работаю с Symfony 4.2,
Я работаю с компонентом безопасности и пытаюсь добавить remember me.
Сначала у меня работало Remember Me, но когда моя пользовательская сущность была настроена, remember me больше не работает,
Мой пользовательский пользователь:
Я подключен к базе данных WordPress, и я не могу внести в нее никаких изменений (я должен только читать), И мне нужно добавить некоторое поле для пользователя, поэтому я должен создать новую таблицу User OneToOne с WpUsers (пользователи WordPress),
Итак, я использую doctrine для создания сущности из существующей базы данных, я не касался этих сущностей, я просто создаю свою пользовательскую сущность, чтобы добавить поле ролей в пользовательскую систему:
Переход WordPress хэшируется с помощью phpass.
Entity WpUsers (сгенерированный doctrine):
/**
* WpUsers
*
* @ORMTable(name="wp_users", indexes={@ORMIndex(name="user_nicename", columns={"user_nicename"}), @ORMIndex(name="user_login_key", columns={"user_login"}), @ORMIndex(name="user_email", columns={"user_email"})})
* @ORMEntity(repositoryClass="AppRepositoryWpUsersRepository")
*/
class WpUsers
{
/**
* @var int
*
* @ORMColumn(name="ID", type="bigint", nullable=false, options={"unsigned"=true})
* @ORMId
* @ORMGeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="user_login", type="string", length=60, nullable=false)
*/
private $userLogin = '';
/**
* @var string
*
* @ORMColumn(name="user_pass", type="string", length=255, nullable=false)
*/
private $userPass = '';
/**
* @var string
*
* @ORMColumn(name="user_nicename", type="string", length=50, nullable=false)
*/
private $userNicename = '';
/**
* @var string
*
* @ORMColumn(name="user_email", type="string", length=100, nullable=false)
*/
private $userEmail = '';
/**
* @var string
*
* @ORMColumn(name="user_url", type="string", length=100, nullable=false)
*/
private $userUrl = '';
/**
* @var DateTime
*
* @ORMColumn(name="user_registered", type="datetime", nullable=false, options={"default"="0000-00-00 00:00:00"})
*/
private $userRegistered = '0000-00-00 00:00:00';
/**
* @var string
*
* @ORMColumn(name="user_activation_key", type="string", length=255, nullable=false)
*/
private $userActivationKey = '';
/**
* @var int
*
* @ORMColumn(name="user_status", type="integer", nullable=false)
*/
private $userStatus = '0';
/**
* @var string
*
* @ORMColumn(name="display_name", type="string", length=250, nullable=false)
*/
private $displayName = '';
EntityUser.php:
<?php
namespace AppEntity;
use DoctrineORMMapping as ORM;
use SymfonyComponentSecurityCoreUserUserInterface;
/**
* @ORMEntity(repositoryClass="AppRepositoryUserRepository")
*/
class User implements UserInterface
{
/**
* @ORMId()
* @ORMGeneratedValue()
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="json_array")
*/
private $roles = [];
/**
* @ORMOneToOne(targetEntity="AppEntityWpUsers", cascade={"persist", "remove"})
* @ORMJoinColumn(name="wp_user_id", referencedColumnName="ID",nullable=false)
*/
private $wpUser;
public function getId(): ?int
{
return $this->id;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUsername(): string
{
return $this->getWpUser()->getUserLogin();
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see UserInterface
*/
public function getPassword()
{
return $this->getWpUser()->getUserPass();
}
/**
* @see UserInterface
*/
public function getSalt()
{
// not needed for apps that do not check user passwords
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getWpUser(): ?WpUsers
{
return $this->wpUser;
}
public function setWpUser(WpUsers $wpUser): self
{
$this->wpUser = $wpUser;
return $this;
}
}
security.yaml:
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
# encoders:
# AppEntityWpUsers:
# algorithm: bcrypt
providers:
# in_memory: { memory: ~ }
app_user_provider:
entity:
class: AppEntityUser
property: wpUser.userLogin
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
authenticators:
- AppSecurityLoginFormAuthenticator
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
Security LoginFormAuthenticator:
namespace AppSecurity;
// use ...
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
// private $passwordEncorder;
private $router;
public function __construct(
EntityManagerInterface $entityManager,
UrlGeneratorInterface $urlGenerator,
CsrfTokenManagerInterface $csrfTokenManager,
// UserPasswordEncoderInterface $passwordEncorder,
// PasswordHash $passwordHash
RouterInterface $router
)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
// $this->passwordEncorder = $passwordEncorder;
$this->router = $router;
$this->passwordHash = new PasswordHash(8,false);
}
public function supports(Request $request)
{
return 'app_login' === $request->attributes->get('_route')
amp;amp; $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'userLogin' => $request->request->get('userLogin'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['userLogin']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$wpUser = $this->entityManager->getRepository(WpUsers::class)->findOneBy(['userLogin' => $credentials['userLogin']]);
if (!$wpUser) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('User Login could not be found.');
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['wpUser' => $wpUser ]);
if(!$user){
$user = new USER();
$user->setWpUser($wpUser);
$this->entityManager->persist($user);
$this->entityManager->flush();
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
// return $this->passwordEncorder->isPasswordValid($user, $credentials['password']);
return $this->passwordHash->CheckPassword($credentials['password'],$user->getPassword());
// Check the user's password or other credentials and return true or false
// If there are no credentials to check, you can just return true
throw new Exception('TODO: check the credentials inside '.__FILE__);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
// For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
// throw new Exception('TODO: provide a valid redirect inside '.__FILE__);
return new RedirectResponse($this->router->generate('commandes'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate('app_login');
}
}
login.twig.html:
{% extends 'myBase.html.twig' %}
{% block title %}Log in!{% endblock %}
{% block body %}
<form method="post">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputUserLogin" class="sr-only">User Login</label>
<input type="text" value="{{ last_username }}" name="userLogin" id="inputUserLogin" class="form-control" placeholder="User Login" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
<!-- Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
See https://symfony.com/doc/current/security/remember_me.html -->
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="_remember_me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary" type="submit">
Sign in
</button>
</form>
{% endblock %}
Ответ №1:
Я полагаю, что вам не хватает supportsRememberMe()
метода проверки подлинности Guard. Как вы можете прочитать в документации:
supportsRememberMe()
If you want to support "remember me" functionality, return true from this method. You will still
need to activate remember_me under your firewall for it to work...
Таким образом, решением должно быть добавление вышеупомянутого метода в ваш аутентификатор:
public function supportsRememberMe()
{
return true;
}
Ответ №2:
Ответ заключается в том, что я должен внедрить пользовательский поставщик, потому что мой процесс загрузки пользователя не связан с прямой сущностью.
создание корзины / консоли: пользователь
И выберите, что пользователь не должен сохраняться в БД, чтобы CLI создал для вас UserProvider.