为什么Symfony Guard会发生火灾和安全问题。每个请求都有活动?

时间:2017-05-24 15:07:58

标签: symfony symfony-3.2

我有一个Symfony 3.2应用程序,它公开REST API并使用Json Web Tokens(JWT)进行身份验证。我最近转而使用Symfony的Guard组件。现在我的security.yml包含防火墙配置部分如下(我使用Lexik JWT捆绑包2.4.0,但这不重要):

firewalls:
    # ...
    api:
        pattern:   ^/api
        stateless: true
        guard:
            authenticators:
               - lexik_jwt_authentication.jwt_token_authenticator

由于我执行了此切换,因此我注意到每个请求都被处理,就像用户刚刚登录一样,即触发了security.interactive_login事件。 在文档(http://symfony.com/doc/current/components/security/authentication.html#authentication-events)中声明:

  

在用户主动进行后触发security.interactive_login事件   登录到您的网站。区分这个动作很重要   非交互式身份验证方法,例如:      认证基于"记住我"曲奇饼,      基于您的会话的身份验证,      使用HTTP基本或HTTP摘要头进行身份验证。   您可以监听security.interactive_login事件,例如,在   每次登录时,都会向您的用户发送欢迎Flash消息。

所以我绝对不希望每个请求都有这个事件 - 我希望在每次请求时都能得到security.authentication.success事件,正如文档中所指出的那样。

但是,Symfony的GuardAuthenticatorHandler类会在security.interactive_login方法中调度authenticateWithToken事件,GuardAuthenticationListener会在每个请求中调用此方法。 这是Symfony的一个错误,我身边的误解,还是错误的配置?

(这不是一个哲学问题 - 在我的情况下,它会导致一个具体问题,即每次请求都会更新用户的上次登录时间,这是没有意义的。)

4 个答案:

答案 0 :(得分:1)

你应该改变这个

        stateless: false

答案 1 :(得分:1)

我遇到了你的问题,因为我遇到了同样的问题。我的解决方法是在请求对象中添加一个属性,在guard的supports方法中返回true之前。

示例:

public function supports(Request $request)
{
    ...

    $request->attributes->set('is_interactive_login', true);

    return true;
}

使用此信息,您可以检查它是否是事件监听器中的交互式登录

示例:

public function onLoginSuccess(InteractiveLoginEvent $event)
{
    $request = $event->getRequest();
    if ($request->attributes->get('is_interactive_login', false)) {
        // do whatever you need todo on interactive login
    }
}

答案 2 :(得分:0)

最好订阅Events::JWT_CREATED事件,因为在通过身份验证进行身份验证后,它已被解雇。

示例:

<?php

namespace App\Event\Subscriber;

use App\Entity\User\User;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AuthenticationSuccessSubscriber implements EventSubscriberInterface
{
    /**
     * @var EntityManager
     */
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public static function getSubscribedEvents()
    {
        return [
            Events::JWT_CREATED => 'onInteractiveLogin',
        ];
    }

    /**
     * @param JWTCreatedEvent $event
     *
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    public function onInteractiveLogin(JWTCreatedEvent $event)
    {
        /** @var User $user */
        $user = $event->getUser();
        $user->setLastLoginAt(new \DateTime());
        $user->resetFailedLogins();
        $this->em->flush($user);
    }
}

答案 3 :(得分:0)

我也遇到了同样的麻烦。就我而言,我对API请求使用Guard身份验证。因此,我绝对不喜欢在任何API请求之后更新用户的last_login。

INTERACTIVE_LOGIN事件是从here分派的。

所以我的肮脏技巧是将此定义添加到应用程序配置的services部分:

security.authentication.guard_handler:
        class: Symfony\Component\Security\Guard\GuardAuthenticatorHandler
        arguments:
            $eventDispatcher: ~

警告

此方法的明显缺点是,您为所有应用程序的后卫 broke 更改处理程序。