gpt4 book ai didi

php - Symfony & 守卫 : "The security token was removed due to an AccountStatusException"

转载 作者:可可西里 更新时间:2023-11-01 12:26:03 26 4
gpt4 key购买 nike

我试图为我的登录表单创建一个身份验证器,但由于某些不明原因,我总是无法登录。

[2016-10-05 18:54:53] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user=\"test@test.test\", authenticated=true, roles=\"ROLE_USER\"))","authenticator":"AppBundle\\Security\\Authenticator\\FormLoginAuthenticator"} []
[2016-10-05 18:54:54] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationExpiredException(code: 0): at /space/products/insurance/vendor/symfony/symfony/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php:86)"} []
[2016-10-05 18:54:54] security.INFO: The security token was removed due to an AccountStatusException. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationExpiredException(code: 0): at /space/products/insurance/vendor/symfony/symfony/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php:86)"} []

我不理解这个“AuthenticationExpiredException”,因为我的应用程序中没有任何无状态的内容,也没有以任何方式过期的内容。

这个问题是否与任何人交谈?


编辑 1

几个小时后,由于 Twig 中的 {{ is_granted('ROLE_USER') }},我似乎没有登录。反正不明白为什么。

编辑2

如果我在 onAuthenticationSuccess 验证器的方法上 dump() 我的安全 token ,authenticated = true

但是,如果我在重定向后或访问新页面时转储()我的安全 token ,'authenticated' = false

为什么我的身份验证没有被存储。


app/config/security.yml

security:

encoders:
AppBundle\Security\User\Member:
algorithm: bcrypt
cost: 12

providers:
members:
id: app.provider.member

role_hierarchy:
ROLE_ADMIN: "ROLE_USER"

firewalls:
dev:
pattern: "^/(_(profiler|wdt|error)|css|images|js)/"
security: false

main:
pattern: "^/"
anonymous: ~
logout: ~
guard:
authenticators:
- app.authenticator.form_login

access_control:
- { path: "^/connect", role: "IS_AUTHENTICATED_ANONYMOUSLY" }
- { path: "^/register", role: "IS_AUTHENTICATED_ANONYMOUSLY" }
- { path: "^/admin", role: "ROLE_ADMIN" }
- { path: "^/user", role: "ROLE_USER" }
- { path: "^/logout", role: "ROLE_USER" }

AppBundle/Controller/SecurityController.php

<?php

namespace AppBundle\Controller;

use AppBundle\Base\BaseController;
use AppBundle\Form\Type\ConnectType;
use AppBundle\Security\User\Member;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;

class SecurityController extends BaseController
{
/**
* @Route("/connect", name="security_connect")
* @Template()
*/
public function connectAction(Request $request)
{
$connectForm = $this
->createForm(ConnectType::class)
->handleRequest($request)
;

return [
'connect' => $connectForm->createView(),
];
}
}

AppBundle/Form/Type/ConnectType.php

<?php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Validator\Constraints;
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue as RecaptchaTrue;

class ConnectType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', Type\EmailType::class, [
'label' => 'Your email',
'required' => true,
'constraints' => [
new Constraints\Length(['min' => 8])
],
])
->add('password', Type\PasswordType::class, [
'label' => 'Your password',
'constraints' => new Constraints\Length(['min' => 8, 'max' => 4096]), /* CVE-2013-5750 */
])
->add('recaptcha', EWZRecaptchaType::class, [
'label' => 'Please tick the checkbox below',
'constraints' => [
new RecaptchaTrue()
],
])
->add('submit', Type\SubmitType::class, [
'label' => 'Connect',
])
;
}
}

AppBundle/Security/Authenticator/FormLoginAuthenticator.php

<?php

namespace AppBundle\Security\Authenticator;

use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use AppBundle\Form\Type\ConnectType;

class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
private $container; // ¯\_(ツ)_/¯

public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

public function getCredentials(Request $request)
{
if ($request->getPathInfo() !== '/connect') {
return null;
}

$connectForm = $this
->container
->get('form.factory')
->create(ConnectType::class)
->handleRequest($request)
;

if ($connectForm->isValid()) {
$data = $connectForm->getData();

return [
'username' => $data['email'],
'password' => $data['password'],
];
}

return null;
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUsername($credentials['username']);
}

public function checkCredentials($credentials, UserInterface $user)
{
$isValid = $this
->container
->get('security.password_encoder')
->isPasswordValid($user, $credentials['password'])
;

if (!$isValid) {
throw new BadCredentialsException();
}

return true;
}

protected function getLoginUrl()
{
return $this
->container
->get('router')
->generate('security_connect')
;
}

protected function getDefaultSuccessRedirectUrl()
{
return $this
->container
->get('router')
->generate('home')
;
}
}

AppBundle/Security/Provider/MemberProvider.php

<?php

namespace AppBundle\Security\Provider;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use AppBundle\Security\User\Member;
use Api\Gateway\RequestResponse\RequestResponseHandlerInterface;
use Api\Business\InsuranceWebsite\Action\GetInsuranceMember\GetInsuranceMemberRequest;
use Api\Gateway\Exception\NoResultException;

class MemberProvider implements UserProviderInterface
{
protected $gateway;

public function __construct(RequestResponseHandlerInterface $gateway)
{
$this->gateway = $gateway;
}

public function loadUserByUsername($username)
{
try {
$response = $this->gateway->handle(
new GetInsuranceMemberRequest($username)
);
} catch (NoResultException $ex) {
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}

$member = new Member();
$member->setId($response->getId());
$member->setUsername($response->getEmail());
$member->setPassword($response->getPassword());
$member->setCompanyId($response->getCompanyId());
$member->setFirstname($response->getFirstname());
$member->setLastname($response->getLastname());
$member->setIsManager($response->isManager());
$member->setIsEnabled($response->isEnabled());

return $member;
}

public function refreshUser(UserInterface $user)
{
if (!$user instanceof Member) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}

return $this->loadUserByUsername($user->getUsername());
}

public function supportsClass($class)
{
return $class === Member::class;
}
}

AppBundle/Security/User/Member.php

<?php

namespace AppBundle\Security\User;

use Symfony\Component\Security\Core\User\UserInterface;

class Member implements UserInterface
{
private $id;
private $username;
private $password;
private $companyId;
private $firstname;
private $lastname;
private $isManager;
private $isEnabled;
private $roles = ['ROLE_USER'];

public function getId()
{
return $this->id;
}

public function setId($id)
{
$this->id = $id;

return $this;
}

public function getUsername()
{
return $this->username;
}

public function setUsername($username)
{
$this->username = $username;

return $this;
}

public function getPassword()
{
return $this->password;
}

public function setPassword($password)
{
$this->password = $password;
return $this;
}

public function getCompanyId()
{
return $this->companyId;
}

public function setCompanyId($companyId)
{
$this->companyId = $companyId;

return $this;
}

public function getFirstname()
{
return $this->firstname;
}

public function setFirstname($firstname)
{
$this->firstname = $firstname;

return $this;
}

public function getLastname()
{
return $this->lastname;
}

public function setLastname($lastname)
{
$this->lastname = $lastname;

return $this;
}

public function isManager()
{
return $this->isManager;
}

public function setIsManager($isManager)
{
$this->isManager = $isManager;

return $this;
}

public function IsEnabled()
{
return $this->isEnabled;
}

public function setIsEnabled($isEnabled)
{
$this->isEnabled = $isEnabled;

return $this;
}

public function eraseCredentials()
{
$this->password = null;
}

public function hasRole($role)
{
return in_array($role, $this->roles);
}

public function getRoles()
{
return $this->roles;
}

public function addRole($role)
{
if (!$this->hasRole($role)) {
$this->roles[] = $role;
}

return $this;
}

public function removeRole($role)
{
$index = array_search($role, $this->roles);
if ($index !== false) {
unset($this->roles[$index]);
$this->roles = array_values($this->roles);
}

return $this;
}

public function getSalt()
{
return null;
}
}

src/AppBundle/Resources/config/services.yml

imports:

parameters:
app.provider.member.class: AppBundle\Security\Provider\MemberProvider
app.authenticator.form_login.class: AppBundle\Security\Authenticator\FormLoginAuthenticator

services:
app.provider.member:
class: %app.provider.member.class%
arguments: ['@gateway']

app.authenticator.form_login:
class: %app.authenticator.form_login.class%
arguments: ["@service_container"]

最佳答案

经过 8 小时的努力,我找到了我的错误。我保证,我会在发表评论后喝大量啤酒!

我在 Symfony\Component\Security\Core\Authentication\Token\AbstractToken::hasUserChanged() 方法中找到了我的问题,该方法将存储在 session 中的用户与 session 返回的用户进行比较您的提供商的 refreshUser

由于这种情况,我的用户实体被认为已更改:

    if ($this->user->getPassword() !== $user->getPassword()) {
return true;
}

事实上,在存储到 session 之前,eraseCredentials() 方法在您的用户实体上被调用,因此密码被删除。但是密码存在于提供者返回的用户中。

这就是为什么在文档中,它们显示 plainPasswordpassword 属性...它们在 session 中保留 password,而 eraseCredentials 只是清理`纯密码。有点棘手。

我们有两个解决方案:

  • eraseCredentials 不涉及密码,如果您想在成员(member)以某种方式更改密码时取消身份验证,这会很有用。

  • 在我们的用户实体中实现 EquatableInterface,因为下面的测试在上面的测试之前调用。

    if ($this->user instanceof EquatableInterface) {
    return !(bool) $this->user->isEqualTo($user);
    }

我决定在我的用户实体中实现 EquatableInterface,以后我永远不会忘记这样做。

<?php

namespace AppBundle\Security\User;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;

class Member implements UserInterface, EquatableInterface
{

// (...)

public function isEqualTo(UserInterface $user)
{
return $user->getId() === $this->getId();
}
}

关于php - Symfony & 守卫 : "The security token was removed due to an AccountStatusException",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39880051/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com