Php Symfony 2-重定向后身份验证令牌丢失
我对symfony2有问题(我在Symfony 2.0和Symfony 2.3上也尝试了同样的方法,只是为了看看这是否是一个Symfony bug),我在身份验证后的下一页加载/重定向中丢失了安全令牌 我已为Symfony 2.3创建了自定义身份验证程序,以使用此处指定的第三方服务进行身份验证: 应用程序使用外部服务进行身份验证,并在回调URL“/success”中设置令牌,我可以从调试栏看到用户已通过身份验证,但当我转到“/”(位于同一防火墙下)时,我得到“SecurityContext中未找到令牌”。错误,用户不再经过身份验证 以下是文件: security.yml NoaUserToken.phpPhp Symfony 2-重定向后身份验证令牌丢失,php,authentication,symfony,Php,Authentication,Symfony,我对symfony2有问题(我在Symfony 2.0和Symfony 2.3上也尝试了同样的方法,只是为了看看这是否是一个Symfony bug),我在身份验证后的下一页加载/重定向中丢失了安全令牌 我已为Symfony 2.3创建了自定义身份验证程序,以使用此处指定的第三方服务进行身份验证: 应用程序使用外部服务进行身份验证,并在回调URL“/success”中设置令牌,我可以从调试栏看到用户已通过身份验证,但当我转到“/”(位于同一防火墙下)时,我得到“SecurityContext中未找
您应该在请求对象上使用会话接口,而不是在NoaListener中使用会话。Symfony自行进行会话管理,可能会忽略或覆盖您的会话(例如,成功登录后迁移会话以防止会话固定攻击是很常见的)
使用您已有的$request=$event->getRequest()
,然后使用$request->getsession()->get('userInfo')
,等等。非常感谢inanimatt注意到,实际上第三方库正在重置会话,我必须重写第三方库中的会话处理来修复此问题。
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
users:
entity: { class: AcmeStoreBundle:User, property: email }
firewalls:
login:
pattern: ^/login$
security: false
noa:
pattern: ^/
provider: users
noa: true
logout:
path: /logout
target: /login
access_control:
- { path: ^/success, roles: IS_AUTHENTICATED_ANONYMOUSLY }
<?php
namespace Acme\StoreBundle\Security\Authentication\Token;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
class NoaUserToken extends AbstractToken
{
public $expires;
public $mobile;
public $email;
public function __construct(array $roles = array())
{
parent::__construct($roles);
parent::setAuthenticated(true);
}
public function getCredentials()
{
return '';
}
}
<?php
namespace Acme\StoreBundle\Security\Authentication\Provider;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\NonceExpiredException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Acme\StoreBundle\Security\Authentication\Token\NoaUserToken;
class NoaProvider implements AuthenticationProviderInterface
{
private $userProvider;
private $cacheDir;
public function __construct(UserProviderInterface $userProvider, $cacheDir)
{
$this->userProvider = $userProvider;
$this->cacheDir = $cacheDir;
}
public function authenticate(TokenInterface $token)
{
$userEmail = $token->getUser();
$user = $this->userProvider->loadUserByUsername($userEmail);
if ($user && $this->validateToken($token->expires) && !$user->getHidden()) {
$authenticatedToken = new NoaUserToken($user->getRoles());
$authenticatedToken->expires = $token->expires;
$authenticatedToken->mobile = $token->mobile;
$authenticatedToken->email = $token->email;
$authenticatedToken->setUser($user);
$authenticatedToken->setAuthenticated(true);
return $authenticatedToken;
}
throw new AuthenticationException('The NOA authentication failed.');
}
protected function validateToken($expires)
{
// Check if the token has expired.
if (strtotime($expires) <= time()) {
return false;
}
}
public function supports(TokenInterface $token)
{
return $token instanceof NoaUserToken;
}
}
<?php
namespace Acme\StoreBundle\Security\Firewall;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Acme\StoreBundle\Security\Authentication\Token\NoaUserToken;
class NoaListener implements ListenerInterface
{
protected $securityContext;
protected $authenticationManager;
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager)
{
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
}
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (! preg_match('/^\/app_dev.php\/success/', $request->getRequestUri())) {
return;
}
if( $this->securityContext->getToken() ){
return;
}
try {
\NOA_Sso_Web::getInstance()->createSession();
}
catch (Exception $e) {
// Handle error situation here
}
if (isset($_SESSION['userInfo'])) {
$token = new NoaUserToken();
$token->setUser($_SESSION['userInfo']['email']);
$token->mobile = $_SESSION['userInfo']['mobileVerified'] ? $_SESSION['userInfo']['mobile'] : null;
$token->email = $_SESSION['userInfo']['emailVerified'] ? $_SESSION['userInfo']['email'] : null;
$token->expires = $_SESSION['tokenInfo']['expires'];
try {
$authToken = $this->authenticationManager->authenticate($token);
$this->securityContext->setToken($authToken);
return;
} catch (AuthenticationException $failed) {
// Do nothing and go for the default 403
}
}
$this->securityContext->setToken(null);
// Deny authentication with a '403 Forbidden' HTTP response
$response = new Response();
$response->setStatusCode(403);
$event->setResponse($response);
}
}
<?php
namespace Acme\StoreBundle\DependencyInjection\Security\Factory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
class NoaFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$providerId = 'security.authentication.provider.noa.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('noa.security.authentication.provider'))
->replaceArgument(0, new Reference($userProvider))
;
$listenerId = 'security.authentication.listener.noa.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('noa.security.authentication.listener'));
return array($providerId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
return 'noa';
}
public function addConfiguration(NodeDefinition $node)
{
}
}
<?php
namespace Acme\StoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
public function indexAction()
{
$token = $this->container->get('security.context')->getToken();
// Not reached
print '<pre>';
print_r($token->getUser());
print '</pre>';
return $this->render('AcmeStoreBundle:Default:index.html.twig', array('name' => $token->getUser()->gerUsername()));
}
public function loginAction()
{
return $this->render('AcmeStoreBundle:Default:login.html.twig', array());
}
public function successAction()
{
$token = $this->container->get('security.context')->getToken();
$this->container->get('event_dispatcher')->dispatch(
SecurityEvents::INTERACTIVE_LOGIN,
new InteractiveLoginEvent($this->container->get('request'), $token)
);
// This prints the user object
print '<pre>';
print_r($token->getUser());
print '</pre>';
return new Response('<script>//window.top.refreshPage();</script>');
}
}