【发布时间】: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 被触发
- 基本上,calls
MyAuthenticator->createToken() - 然后calls
AuthenticationManager->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