【问题标题】:Best way to handle ephemeral tokens when using SimplePreAuthenticator & PreAuthenticatedToken使用 SimplePreAuthenticator 和 PreAuthenticatedToken 时处理临时令牌的最佳方式
【发布时间】:2016-03-13 02:46:10
【问题描述】:

我正在使用此处描述的 SimpleAuthentication 功能:http://symfony.com/doc/2.6/cookbook/security/api_key_authentication.html

目的是通过作为查询(get)参数或标头传递的令牌字符串提供身份验证。这个令牌,我们称之为 TemporaryAccessToken 以避免与 Sf2 令牌混淆,由控制器生成,通过电子邮件发送给用户(此处未描述)并且应该在有限的时间内可用(专用实体中有一个 valid_until \DateTime 列)。

作为记录,当受保护的页面(通过simple_user_account防火墙)第一次被访问时,身份验证过程如下:

  • SimplePreAuthenticationListener 被触发
  • 基本上,callsMyAuthenticator->createToken()
  • 然后callsAuthenticationManager->authenticate(),其中callsMyAuthenticator->authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)

问题是:一旦用户通过身份验证,并且因为我在防火墙配置中使用stateless: false,身份验证过程不会再次触发,因为会话中已经存在有效的 Sf2 令牌。

我看到了 2 个逻辑解决方案,但我不知道如何正确地做到这一点:

  • 使会话在我的TemporaryAccessToken.valid_until 列中设置的日期之前有效。有没有办法“本机”实现这一目标? (我看到remember_me防火墙有一个lifetime参数)
  • ,能够重新检查 TemporaryAccessToken 有效性(请参阅我的身份验证器中的if( $accessToken && $accessToken->isValid() ) 行)

app/config/security.yml

firewalls:
    simple_user_account:
        pattern:   ^/account/access
        stateless:  false
        simple_preauth:
            authenticator: app.security.simple_user_authenticator
        logout:
            path:   /logout_simple
            target: /

我的验证器类看起来像:

class SimpleUserAuthenticator implements SimplePreAuthenticatorInterface, AuthenticationFailureHandlerInterface
{
    /**
     * @var AccessTokenManager
     */
    private $accessTokenManager;

    /**
     * SimpleUserAuthenticator constructor.
     * @param AccessTokenManager $accessTokenManager
     */
    public function __construct(AccessTokenManager $accessTokenManager)
    {
        $this->accessTokenManager = $accessTokenManager;
    }

    public function createToken(Request $request, $providerKey)
    {
        $TemporaryAccessToken = $request->query->get('simple_user_token');
        if (!$TemporaryAccessToken) {
            throw new BadCredentialsException('No simple_user token found');
        }

        return new PreAuthenticatedToken(
            'anonymous',
            $TemporaryAccessToken,
            $providerKey
        );
    }


    public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
    {
        if( $token->getUser() instanceof SimpleUser )
        {
            $newToken = new PreAuthenticatedToken(
                $token->getUser(),
                $token->getCredentials(),
                $providerKey,
                array('ROLE_USER')
            );
            return $newToken;
        }

        $accessToken = $this->accessTokenManager->getRepository()->findOneByToken($token->getCredentials());
        if( $accessToken && $accessToken->isValid() )
        {
            $user = $userProvider->loadUserByUsername($accessToken->getAccount()->getEmailCanonical());
            $newToken = new PreAuthenticatedToken(
                $user,
                $token->getCredentials(),
                $providerKey,
                array('ROLE_USER')
            );
            return $newToken;
        }
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        $response =  new RedirectResponse(
            '/login'
        );
        return $response;
    }

    public function supportsToken(TokenInterface $token, $providerKey)
    {
        return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
    }


}

Symfony2 版本:2.5.6

【问题讨论】:

  • 我的问题有什么不清楚的地方吗?
  • 如果您设置stateless: true,那么您每次访问防火墙时都需要对用户进行身份验证。但是无状态防火墙不会在会话中保留任何内容。如果这些信息对你没有用,请直接告诉我,你需要什么。我不确定您是否正确理解。
  • 这就是重点,我想使用 stateless: false 能够让我的用户登录到会话中(因为他将能够在通过身份验证后导航到其他页面,而无需传递 TemporaryAccessToken再次)。问题是,当它完成时,它就完成了。在每个后续请求中,我希望能够查看我的 TemporaryAccessToken 对于存储在处理此令牌的实体中的日期是否仍然有效。 SimplePreAuthListenner 不会再次触发,我的 SimpleUserAuthenticator 也是如此。
  • 另一种解决方案是强制超时,基本上是TemporaryAccessToken.valid_until - now(),但不确定如何以正确的方式做到这一点(并且不确定这是要走的路......)
  • 恕我直言,检查您的令牌是否有效仅在防火墙无状态时才有意义。另一种解决方案:正确配置会话 cookie 并设置会话 cookie 过期的时间。

标签: php symfony security authentication


【解决方案1】:

好吧,如果你需要使用会话,你可以在你的config.yml会话设置下设置lifetime

# config.yml
framework:

    session:
        # handler_id set to null will use default session handler from php.ini
        handler_id: ~
        lifetime: 3600

您可以在几秒钟内将 lifetime 值更改为任何值(默认为 3600 或 1 小时)

另外,您可以尝试configure garbage collector

如果这个答案没有帮助,请告诉我。

【讨论】:

  • 问题是用户登录时必须计算cookie的生存期
  • @foobar 在每个身份验证上创建新会话文件,afaik。
  • 在身份验证工作流程中如何动态设置 cookie 生命周期?
  • @foobar 也许这会对您有所帮助stackoverflow.com/questions/23362701/…,但是您是否测试过我之前的评论?身份验证后应该创建生命周期为 3600 的新会话,不是吗?
  • 不行,创建会话时,必须根据当前日期和TemporaryAccessToken.valid_until日期计算生命周期。
猜你喜欢
  • 2012-11-16
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
相关资源
最近更新 更多