Symfony 5:如何在登录前检查用户是不是被禁止

Posted

技术标签:

【中文标题】Symfony 5:如何在登录前检查用户是不是被禁止【英文标题】:Symfony 5 : how to check if user is banned or not before loginSymfony 5:如何在登录前检查用户是否被禁止 【发布时间】:2021-01-04 20:04:15 【问题描述】:

我正在开发一个 symfony 5 项目和一个带有安全组件的身份验证系统,我在我的用户实体中添加了一个名为 is_banned 的字段,默认情况下它采用 false 值,我想放置一个函数来检查是否用户在登录之前是否被禁止,如果是,则应用将其重定向到主页并显示简单的错误消息!

<?php

namespace App\Entity;

/**
 * @ORM\Entity(repositoryClass=UserRepository::class)
 * @UniqueEntity(fields="email", message="There is already an account with this email")
 */
class User implements UserInterface


    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     */
    private $email;

    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isVerified = false;


    /**
     * @ORM\Column(type="boolean")
     */
    private $is_banned = false;




    public function __construct()
    
        $this->bookings = new ArrayCollection();
        $this->roles = array('ROLE_USER');
    

    public function getId(): ?int
    
        return $this->id;
    

    public function getEmail(): ?string
    
        return $this->email;
    

    public function setEmail(string $email): self
    
        $this->email = $email;

        return $this;
    

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    
        return (string) $this->email;
    

    /**
     * @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(): string
    
        return (string) $this->password;
    

    public function setPassword(string $password): self
    
        $this->password = $password;

        return $this;
    

    /**
     * @see UserInterface
     */
    public function getSalt()
    
        // not needed when using the "bcrypt" algorithm in security.yaml
    

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    

    public function isVerified(): bool
    
        return $this->isVerified;
    

    public function setIsVerified(bool $isVerified): self
    
        $this->isVerified = $isVerified;

        return $this;
 
 
    public function getIsBanned(): ?bool
    
        return $this->is_banned;
    

    public function setIsBanned(bool $is_banned): self
    
        $this->is_banned = $is_banned;

        return $this;
    
    



<?php

namespace App\Security;

class UserAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface

    use TargetPathTrait;

    public const LOGIN_ROUTE = 'app_login';

    private $entityManager;
    private $urlGenerator;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
    
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    

    public function supports(Request $request)
    
        return self::LOGIN_ROUTE === $request->attributes->get('_route')
            && $request->isMethod('POST');
    

    public function getCredentials(Request $request)
    
        $credentials = [
            'email' => $request->request->get('email'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['email']
        );

        return $credentials;
    

    public function getUser($credentials, UserProviderInterface $userProvider)
    
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) 
            throw new InvalidCsrfTokenException();
        

        $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
        if (!$user) 
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('Email could not be found.');
        


        return $user;
    


    public function checkCredentials($credentials, UserInterface $user)
    
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    

    /**
     * Used to upgrade (rehash) the user's password automatically over time.
     * @param $credentials
     * @return string|null
     */
    public function getPassword($credentials): ?string
    
        return $credentials['password'];
    

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) 
            return new RedirectResponse($targetPath);
        



        return new RedirectResponse($this->urlGenerator->generate('car.index'));
        //throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
    

    protected function getLoginUrl()
    
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    

【问题讨论】:

那么你有什么尝试?你知道你生成的验证器实际上在做什么吗?授权应该是身份验证的一部分吗? 【参考方案1】:

您可以使用用户检查器。它会在登录表单上抛出错误:

config/packages/security.yaml

security:
  ...
  firewalls:
    ...
    main:
      ...
      user_checker: App\Security\UserChecker

App\Security\UserChecker

namespace App\Security;

use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class UserChecker implements UserCheckerInterface


    public function checkPreAuth(UserInterface $user)
    
        if ($user->getIsBanned()) 
            throw new CustomUserMessageAuthenticationException("You're banned !");
        
    

    public function checkPostAuth(UserInterface $user)
    

    


【讨论】:

以上是关于Symfony 5:如何在登录前检查用户是不是被禁止的主要内容,如果未能解决你的问题,请参考以下文章

Symfony - 如何将用户重定向到登录后访问的最后一个页面?

如何使用 MVC 5 在基于令牌的身份验证中检查用户是不是从控制器登录?

Symfony 3 通过手机阵列登录

如何在事件订阅者中访问Symfony 3.3中的登录用户,而不会丢失Web分析器

Symfony3 onSecurityInteractiveLogin注销并设置flash

检查“其他”用户是不是使用 Laravel 5 登录/注销