![](/img/trans.png)
[英]symfony 2.8 - session lost after success login redirect ( there is 2 session id in cookie )
[英]Symfony 2.8 session lost after login_check redirect
我目前正在使用Symfony的組件將舊的自定義框架移植到基於Symfony的自定義框架。 到目前為止,除了登錄部分之外,其他所有事情都進行得很順利。 以下是有關該項目的一些詳細信息:
當用戶嘗試使用表單登錄到管理區域時,就會出現問題。 提交表單后,用戶將被轉發到login_check路由,在此路由中成功檢查了所有憑據。 設置了用戶角色ROLE_ADMIN,最后將用戶重定向到安全頁面,但隨后自動將其重定向回到登錄名。 事件的順序如下:
登錄->登錄檢查->管理員->登錄
我已經通過在ContextListener :: OnKernelResponse中設置斷點進行了一些調試,結果發現令牌從未保存在會話中,因為該方法返回此處:
if (!$event->getRequest()->hasSession()) {
return;
}
另外,我能夠看到將會話添加到數據庫表中,並且會話ID在整個重定向過程中保持不變。 最后,我被彈回到登錄頁面,我的用戶設置為.anon / login_check和/ admin之間的某個位置,我的令牌丟失了。
我已經沒有足夠的想法來調試它了。 我正在粘貼一些代碼以幫助您了解我的設置,但是我認為這些都很好。
我的防火牆配置看起來像這樣
return[
'security'=>[
//Providers
'providers'=>[
'user' => array(
'id' => 'security.user.provider.default',
),
],
//Encoders
'encoders'=>[
'Library\\Security\\Users\\User::class' => array('algorithm' => 'bcrypt', 'cost'=> 15)
],
'firewalls'=>
[
'backend'=>array(
'security' =>true,
'anonymous' => true,
'pattern' => '^/',
'guard' => array(
'authenticators' => array(
'security.guard.form.authenticator',
'security.authenticator.token'
),
'entry_point'=>'security.guard.form.authenticator'
),
),
],
'access_control'=>array(
array('path' => '^/admin', 'roles' => ['ROLE_ADMIN']),
array('path' => '^/api', 'roles' => ['ROLE_API']),
array('path' => '^/pos', 'roles' => ['ROLE_POS']),
array('path' => '^/dashboard', 'roles' => ['ROLE_SUPER_ADMIN']),
array('path' => '^/login', 'roles' => ['IS_AUTHENTICATED_ANONYMOUSLY']),
array('path' => '/', 'roles' => ['IS_AUTHENTICATED_ANONYMOUSLY']),
)
]];
我的用戶界面 :
class User implements UserInterface, EquatableInterface{
private $username;
private $password;
private $salt;
private $roles;
public function __construct($username, $password, $salt, array $roles)
{
$this->username = $username;
$this->password = $password;
$this->salt = $salt;
$this->roles = $roles;
}
public function getRoles()
{
return $this->roles;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return $this->salt;
}
public function getUsername()
{
return $this->username;
}
public function eraseCredentials()
{
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof DefaultUserProvider) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->salt !== $user->getSalt()) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}}
我UserProvider
namespace Library\Security\UserProviders;
use Library\Nosh\Project\Project;
use Library\Security\Users\User;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use PDO;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
class DefaultUserProvider implements UserProviderInterface{
private $db;
private $project;
public function __construct(\PDO $db, Project $project)
{
$this->db = $db;
$this->project=$project;
}
public function loadUserByUsername($username)
{
$projectId = $this->project->id();
$statement = $this->db->prepare("SELECT * FROM users WHERE :userLogin IN (user_login, user_email) AND project_id=:project_id AND user_active=:user_active");
$statement->bindParam(':userLogin', $username, PDO::PARAM_STR);
$statement->bindValue(':user_active', 1, PDO::PARAM_INT);
$statement->bindValue(':project_id', $projectId, PDO::PARAM_INT);
$statement->execute();
if (!$user = $statement->fetch()) {
throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
$roles = explode(',', $user['user_roles']);
return new User($user['user_login'], $user['user_password'],$salt='',$roles);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'Library\\Security\\Users\\User';
}
}
經過幾天的調試,我能夠解決自己的問題。 我沒有會話的原因是因為我無法實現SessionListener來將會話存儲到請求中。 對於使用Symfony Framework或Silex的任何人來說,這都不是問題。 這對我來說只是一個問題,因為我實際上是從頭開始創建一些東西。
對於想知道如何執行此操作的任何人,以下是必要的步驟:
請參閱下面的示例:
SessionListener
use Symfony\Component\HttpKernel\EventListener\SessionListener as AbstractSessionListener;
class SessionListener extends AbstractSessionListener {
private $container;
public function __construct(Container $container)
{
$this->container=$container;
}
protected function getSession()
{
if (!$this->container->has('session')) {
return;
}
return $this->container->get('session');
}
}
SessionServiceProvider
use Core\Container;
use Interfaces\EventListenerProviderInterface;
use Interfaces\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class SessionServiceProvider implements ServiceProviderInterface, EventListenerProviderInterface {
protected $options=[
'cookie_lifetime'=>2592000,//1 month
'gc_probability'=>1,
'gc_divisor'=>1000,
'gc_maxlifetime'=>2592000
];
public function register(Container $container){
switch($container->getParameter('session_driver')){
case 'database':
$storage = new NativeSessionStorage($this->options, new PdoSessionHandler($container->get('db')));
break;
case 'file':
$storage = new NativeSessionStorage($this->options, new NativeFileSessionHandler($container->getParameter('session_dir')));
break;
default:
$storage = new NativeSessionStorage($this->options, new NativeFileSessionHandler($container->getParameter('session_dir')));
break;
}
$container->register('session',Session::class)->setArguments([$storage]);
}
public function subscribe(Container $container, EventDispatcherInterface $dispatcher)
{
$dispatcher->addSubscriber(new SessionListener($container));
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.