Symfony 4 - 自定义 GuardAuthenticator 不设置记住我的 cookie
Symfony 4 - Custom GuardAuthenticator doesn't set remember me cookie
我正在构建自定义 GuardAuthenticator 以在特定路由上使用令牌登录。根据 documentation if supportsRememberMe()
returns true
and remember_me
is activated in the firewall, remember me cookie should be set, 但事实并非如此(尽管它如果我在另一条路线上使用表单登录身份验证,则会设置)。
路线:
/**
* @Route("/login/token/{id}/{token}/{force}", defaults={"force"=0}, name="login_token")
*/
public function loginToken()
{
}
GuardAuthenticator:
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class TokenLoginAuthenticator extends AbstractGuardAuthenticator
{
use TargetPathTrait;
private $em;
private $force;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function supports(Request $request)
{
return 'login_token' === $request->attributes->get('_route') && $request->isMethod('GET');
}
public function getCredentials(Request $request)
{
$credentials = [
'id' => $request->attributes->get('id'),
'token' => $request->attributes->get('token')
];
$this->force = $request->attributes->get('force');
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$user = $this->em->getRepository(User::class)->find($credentials['id']);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('No user found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
if ($user->getToken() === $credentials['token']) {
return true;
}
throw new HttpException(403, "Forbidden");
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
throw new HttpException(403, "Forbidden");
}
public function start(Request $request, AuthenticationException $authException = null)
{
}
public function supportsRememberMe()
{
return true;
}
}
安全配置:
security:
encoders:
App\Entity\User:
id: 'App\Security\PasswordEncoder'
providers:
in_memory: { memory: ~ }
orm:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
form_login:
login_path: login
check_path: login
provider: orm
csrf_token_generator: security.csrf.token_manager
default_target_path: homepage
logout:
path: /logout
target: /
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
# by default, the feature is enablered by checking a
# checkbox in the login form (see below), uncomment the
# following line to always enable it.
# always_remember_me: true
guard:
provider: orm
authenticators:
- App\Security\TokenLoginAuthenticator
如果满足以下 所有 条件,将设置记住我 cookie:
supportsRememberMe()
方法returnstrue
.
- 防火墙中的
remember_me
键已配置。
- (默认)
_remember_me
参数在请求中发送。这通常是通过在登录表单中有一个 _remember_me
复选框来完成的(但它可以作为 url 参数(?_remember_me=1
)发送,或者我们可以配置防火墙 remember_me
键至 always_remember_me
.
onAuthenticationSuccess()
方法 returns 响应对象。
在 Symfony 5.2.6 中,不要忘记将新的 RememberMeBadge() 添加到身份验证函数中:
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
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')),
new RememberMeBadge(),
]
);
}
}
我正在构建自定义 GuardAuthenticator 以在特定路由上使用令牌登录。根据 documentation if supportsRememberMe()
returns true
and remember_me
is activated in the firewall, remember me cookie should be set, 但事实并非如此(尽管它如果我在另一条路线上使用表单登录身份验证,则会设置)。
路线:
/**
* @Route("/login/token/{id}/{token}/{force}", defaults={"force"=0}, name="login_token")
*/
public function loginToken()
{
}
GuardAuthenticator:
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class TokenLoginAuthenticator extends AbstractGuardAuthenticator
{
use TargetPathTrait;
private $em;
private $force;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function supports(Request $request)
{
return 'login_token' === $request->attributes->get('_route') && $request->isMethod('GET');
}
public function getCredentials(Request $request)
{
$credentials = [
'id' => $request->attributes->get('id'),
'token' => $request->attributes->get('token')
];
$this->force = $request->attributes->get('force');
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$user = $this->em->getRepository(User::class)->find($credentials['id']);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('No user found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
if ($user->getToken() === $credentials['token']) {
return true;
}
throw new HttpException(403, "Forbidden");
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
throw new HttpException(403, "Forbidden");
}
public function start(Request $request, AuthenticationException $authException = null)
{
}
public function supportsRememberMe()
{
return true;
}
}
安全配置:
security:
encoders:
App\Entity\User:
id: 'App\Security\PasswordEncoder'
providers:
in_memory: { memory: ~ }
orm:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
form_login:
login_path: login
check_path: login
provider: orm
csrf_token_generator: security.csrf.token_manager
default_target_path: homepage
logout:
path: /logout
target: /
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
# by default, the feature is enablered by checking a
# checkbox in the login form (see below), uncomment the
# following line to always enable it.
# always_remember_me: true
guard:
provider: orm
authenticators:
- App\Security\TokenLoginAuthenticator
如果满足以下 所有 条件,将设置记住我 cookie:
supportsRememberMe()
方法returnstrue
.- 防火墙中的
remember_me
键已配置。 - (默认)
_remember_me
参数在请求中发送。这通常是通过在登录表单中有一个_remember_me
复选框来完成的(但它可以作为 url 参数(?_remember_me=1
)发送,或者我们可以配置防火墙remember_me
键至always_remember_me
. onAuthenticationSuccess()
方法 returns 响应对象。
在 Symfony 5.2.6 中,不要忘记将新的 RememberMeBadge() 添加到身份验证函数中:
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
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')),
new RememberMeBadge(),
]
);
}
}