我可以在symfony中创建类似于isGranted的东西吗?

时间:2020-06-20 02:02:24

标签: php symfony symfony4 symfony-security

所以基本上我想创建类似@IsGranted的东西。 我在应用程序上使用了@IsGranted来访问控制,以防止简单的用户访问例如管理页面。

在我的实体上,我有一个名为is_Active的布尔字段

  • 如果为真(1),则用户可以使用其帐户
  • 如果它为假(0),那么他将被重定向到错误页面!

在这种情况下,我不会在用户的Roles字段上进行测试,但是我将在is_Active字段上进行测试,这就是为什么使用@IsGranted

我创建了一个错误树枝页面active.html.twig 并将其放在模板文件夹中,我发现自己被迫在每个控制器功能上添加这两行。

if ($this->getUser()->getIsActive()==false) {
     return $this->render('active.html.twig');}

这里是一个例子:

/**
 * @IsGranted("ROLE_ADMIN")
 * @Route("/", name="user_index", methods={"GET"})
 */
public function index(UserRepository $userRepository): Response
{
    if ($this->getUser()->getIsActive()==false) {
        return $this->render('active.html.twig');}
            
    return $this->render('user/index.html.twig', [
        'users' => $userRepository->findAll(),
    ]);
}

在每个函数上添加此if语句非常繁琐且不好(我的应用程序中有+30个函数)

也许我可以创建类似于@IsGranted的东西并将其用于每个函数的注释?

2 个答案:

答案 0 :(得分:3)

您可以将@IsGranted与自定义选民一起使用。 https://symfony.com/doc/current/security/voters.html#creating-the-custom-voter

像文档中一样创建新的选民

public const ACTIVE = 'active';

protected function supports(string $attribute, $subject)
{
    return $attribute === self::ACTIVE;
}

protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token)
{
    $user = $token->getUser();

    if ($user instanceof User && !$user->isActive()) {
        throw new InactiveUserException();
    }

    return true;
}

然后,您可以为InactiveUserException创建一个侦听器,并向客户端显示您想要的内容。

在您的控制器中,您需要将@IsGranted("active")@Security(expression="is_granted('active')")放在route方法或控制器之前

答案 1 :(得分:1)

我将为此使用身份验证,那么您不必触摸控制器。您可以检查它们是否已登录并处于活动状态,然后可以查看内容,或者如果它们通过身份验证失败,则可以使用active.html.twig将它们定向到另一条路由。

您也可以只在某些或所有路线上设置此设置。

https://symfony.com/doc/current/security/guard_authentication.html

对身份验证器进行采样,并仅针对您的管理路由进行设置,这样您就可以拥有普通的身份验证器,而无需在所有其他路由的checkCredentials上检查活动用户。

<?php

namespace App\Security;

use App\Entity\User;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
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 Twig\Environment;

class AdminAuthenticator extends AbstractGuardAuthenticator
{
    /** @var Environment */
    private $twig;

    public function __construct(Environment $twig)
    {
        $this->twig = $twig;
    }

    public function supports(Request $request): bool
    {
        $email = $request->request->get('email');
        $password = $request->request->get('password');

        return $email && $password;
    }

    public function getCredentials(Request $request)
    {
        $email = $request->request->get('email');
        $password = $request->request->get('password');

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

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

    public function checkCredentials($credentials, UserInterface $user)
    {
        $password = $credentials['password'];
        if (!$this->passwordEncoder->isPasswordValid($user, $password)) {
            throw new CustomUserMessageAuthenticationException(
                'Sorry, you\'ve entered an invalid username or password.'
            );
        }
        
        if (!$user->isActive()) {
            throw new NotActiveUserException(
                'This account is not active'
            );
        }

        return true;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        if ($exception instanceof NotActiveUserException) {

            // You should redirect here but you get the idea!
            $this->twig->render('active.html.twig');
        }
        
        // Do something else for any other failed auth
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        return new JsonResponse('success', Response::HTTP_OK);
    }

    public function start(Request $request, AuthenticationException $authException = null)
    {
        return new JsonResponse('Not Authorized', Response::HTTP_UNAUTHORIZED);
    }

    public function supportsRememberMe()
    {
        return false;
    }
}

然后在您的security.yaml中

    firewalls:
        admin:
            pattern: ^/admin
            provider: user
            guard:
                authenticators:
                    - App\Security\AdminAuthenticator