Symfony 2.8 session lost after login_check redirect -
i porting old custom framework symfony-based custom framework using symfony's components. far going smoothly, except login part. here few details project:
- i'm using symfony security component v2.8
- my sessions being stored in database using pdosessionhandler
- i'm using guard authenticate users.
the problem arises when user tries login admin area using form. after form submission, user forwarded login_check route credentials checked. user role role_admin set , user redirected secure page, gets redirected automatically login. order of events so:
login -> login_check -> admin -> login
i have done debugging setting breakpoints in contextlistener::onkernelresponse , found out token never saved in session,because method returns here:
if (!$event->getrequest()->hassession()) { return; }
also, able see session being added database table , session id remains constant throughout redirect. in end bounced login page , user set .anon somewhere between /login_check , /admin token lost.
i have run out of ideas on how debug this. pasting code idea of setup, think these fine.
my firewall configuration looking this
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']), ) ]];
my userinterface:
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; }}
my 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 * users :userlogin in (user_login, user_email) , project_id=:project_id , 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" 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" not supported.', get_class($user))); } return $this->loaduserbyusername($user->getusername()); } public function supportsclass($class) { return $class === 'library\\security\\users\\user'; } }
i able solve own problem after several days of debugging. reason had no session because had failed implement sessionlistener store session request. should not issue using symfony framework or silex. issue me, because creating scratch.
for wondering how this, here necessary steps:
- create class extends symfony\component\httpkernel\eventlistener\sessionlistener
- implement method getsession()
- make sure add class dispatcher addsubscriber()
see example below:
sessionlistener
use symfony\component\httpkernel\eventlistener\sessionlistener 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)); } }
Comments
Post a Comment