Php 我是否可以创建类似于在symfony中授予的IsPermited的内容?

Php 我是否可以创建类似于在symfony中授予的IsPermited的内容?,php,symfony,symfony4,symfony-security,Php,Symfony,Symfony4,Symfony Security,所以基本上我想创建类似于@isgrated的东西。 例如,我在应用程序中使用了@isgrated来访问控制,以防止简单用户访问管理员页面 在我的实体上,有一个名为的布尔字段处于活动状态 如果这是真的(1),那么用户可以使用他的帐户 如果为false(0),则他将被重定向到错误页面 在这种情况下,我不打算测试用户的角色字段,而是测试是否处于活动状态字段,这就是为什么我不能使用@isgrated 我创建了一个错误的twig页面active.html.twig 我把它放在templates文件夹中

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

在我的实体上,有一个名为
的布尔字段处于活动状态

  • 如果这是真的(1),那么用户可以使用他的帐户
  • 如果为false(0),则他将被重定向到错误页面
在这种情况下,我不打算测试用户的
角色
字段,而是测试
是否处于活动状态
字段,这就是为什么我不能使用
@isgrated

我创建了一个错误的twig页面
active.html.twig
我把它放在templates文件夹中,我发现自己不得不在每个控制器函数上添加这两行代码

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个函数)


也许我可以创建类似于isgrated的东西,并在每个函数的注释中使用它?

我会使用身份验证,这样您就不必触摸控制器了。您可以检查他们是否已登录并处于活动状态,然后他们可以查看内容,或者如果他们身份验证失败,则您可以使用active.html.twig将他们引导到另一个路由

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

示例验证器并仅为您的管理路由设置此验证器,然后您就可以使用普通验证器,而无需在所有其他路由的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;
    }
}

我会使用身份验证,这样你就不必触摸你的控制器了。您可以检查他们是否已登录并处于活动状态,然后他们可以查看内容,或者如果他们身份验证失败,则您可以使用active.html.twig将他们引导到另一个路由

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

示例验证器并仅为您的管理路由设置此验证器,然后您就可以使用普通验证器,而无需在所有其他路由的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;
    }
}

您可以继续使用@isgrant和自定义投票人

在文档中创建新的投票者

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
创建一个侦听器,并向客户端显示您想要的内容


在您的控制器中,您需要在路由方法或控制器之前放置
@isgrated(“active”)
@Security(expression=“is_grated('active')”)
,您可以继续与自定义投票者一起使用@isgrated

在文档中创建新的投票者

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
创建一个侦听器,并向客户端显示您想要的内容


在您的控制器中,您需要在路由方法或控制器之前放置
@isgrated(“active”)
@Security(expression=“is_grated('active')”)
,以便防止非活动管理员用户通过?看起来很奇怪。如果用户::getRoles不处于活动状态,您可以调整其不返回ROLE\u ADMIN。@Cerad我喜欢这个想法。但问题是,当用户登录时,他将获得我的自定义503(拒绝访问)错误页面!虽然我想让他获得我的active.twig.html错误页面。那么非活动用户可以登录吗?是的,他们可以登录,但登录后会出现一个错误页面,(您的帐户不活动)message+按钮可供登录查看,以便阻止非活动管理员用户通过?看起来很奇怪。如果用户::getRoles不处于活动状态,您可以调整其不返回ROLE\u ADMIN。@Cerad我喜欢这个想法。但问题是,当用户登录时,他将获得我的自定义503(拒绝访问)错误页面!虽然我想让他获得我的active.twig.html错误页面。那么非活动用户可以登录吗?是的,他们可以登录,但登录后会出现一个错误页面,(您的帐户不活动)message+按钮登录。我对否决投票的原因感兴趣,因为据我所知,这正是身份验证系统的用途。当您想授权软件的大部分时,最好编写身份验证来管理它,这样您就不必向每个控制器方法/多个控制器添加任意代码。嗨,James,谢谢您的回答。我并不是真正投反对票的人,所以我不知道为什么_(ツ)_/“@James也不是下一个投票人,但我真的不认为在这里使用guard系统是可行的。也许如果您发布了一些代码,它可能会有所帮助。当然,我也不太明白海报想要什么。但是,也许您的意思是建议一个内核控制器事件侦听器,它将在调用控制器和然后可以用于检查活动属性,并在需要时重定向。但是,一点代码有助于阻止失败的投票者。感谢各位的回复,我添加了一个代码示例来说明我的意思,因此我希望它更清楚。我对失败的原因感兴趣,因为我理解这正是身份验证系统的用途。当您想授权大部分软件时,最好编写身份验证来管理它,这样您就不必向每个控制器方法/多个控制器添加任意代码。嗨,James,谢谢您的回答。我不是真正否决它的人,所以我不知道为什么_(ツ)_/“@James也不是下一个投票人,但我真的不认为在这里使用guard系统是可行的。也许如果您发布了一些代码,它可能会有所帮助。当然,我也不太明白海报想要什么。但是,也许您的意思是建议一个内核控制器事件侦听器,它将在调用控制器和然后可以用于检查活动属性,并在需要时重定向。但是,一点代码有助于保持