I'm trying to set a cookie within a login controller to achieve "remember me" system. Even though I've used the exact code I found on the web, things for me are going wrong. I hope you can help me figure out what I'm missing.
Let's go through the code:
public function loginAction(Request $request) {
// Receiving the login form
// Get Doctrine, Get EntityManager, Get Repository
if(/* form information matche database information */) {
// Creating a session => it's OK
// Creating the cookie
$response = new Response();
$response->headers->setCookie(new Cookie("user", $user));
$response->send();
$url = $this->generateUrl('home');
return $this->redirect($url);
} else
return $this->render('***Bundle:Default:Login.html.php');
}
I included these:
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;
Note that logging-in works fine, the session has been created, but the cookie hasn't.
Instead of:
$response->send();
try to use:
$response->sendHeaders();
After this you should be able to redirect.
By default Symfony\Component\HttpFoundation\Cookie is created as HttpOnly, which triggers security measures in supporting browsers; this helps mitigate certain XSS attacks possible in javascript.
To expose the cookie in such a browser set $httpOnly argument to false:
new Cookie('user', $user, 0, '/', null, false, false); //last argument
It's worth noting that at the time of this edit the framework is configured to not use HttpOnly cookies by default: see the cookbook (cookie_httponly).
Related
I am programming an application that uses ReactJs for the front-end in localhost:3001 and Symfony for the back-end localhost:3000, and to enable cross origin communication I use "cors-bundle" in Symfony.
Now I want to create a Cookie when a user log in, but it doesn't seem to be created !
Thanks for your help,
This is the code in Symfony the moment a user logs in :
use Symfony\Component\HttpFoundation\Cookie;
$cookie = new Cookie( 'my_cookie', 1, strtotime('tomorrow') );
$res = new Response();
$res->headers->setCookie( $cookie );
return new JsonResponse($res);
This what I also tried :
$res->headers->setCookie(Cookie::create('my_cookie', 1));
return new JsonResponse($res);
What you need is:
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class YourClass extends AbstractController {
public function yourMethod(Request $request) {
$cookie = new Cookie(
"cookie_name_here", // Cookie name
1, // Cookie content
(new DateTime('now'))->modify("+1 day"), // Expiration date
"/", // Path
"localhost", // Domain
$request->getScheme() === 'https', // Secure
false, // HttpOnly
true, // Raw
'Strict' // SameSite policy
);
$res = new JsonResponse();
$res->headers->setCookie($cookie);
return $res;
}
}
Things to note here.
Setting the "Secure" flag will mean this cookie is only transmitted on a HTTPS connection. Do not neglect this in production. You may want to use $request->getScheme() === 'https' as the parameter evaluation.
The "HttpOnly" flag is for security and stops Javascipt and Browser extensions from accessing the cookie. If you're using XHR to make requests (for instance, Axios) and include "withCredentials" then this is ok to set as true and will be sent anyway. If you want to read the value in React then set this to false
It should be
$res = new JsonResponse();
$res->headers->setCookie($cookie);
Return $res;
I've not experienced any difference in doing this from Symfony 2. This has already been answered here: How to attach cookies to JSON Response in symfony2?
Have you checked your browser's developer tools to see if a cookie is arriving in the response? Specifically look at the Network tab and monitor the headers of the AJAX response.
I'm trying to implement a SessionProvider auth plugin for a mediawiki install.
I'm trying to integrate with an existing auth system that uses $_SESSION to indicate that a user is logged in, however any method I try, the resulting $_SESSION variable that I get inside the class' provideSessionInfo function is empty.
Previously this was done with a onUserLoadFromSession hook (that contained the bulk of the logic code below), but the update appears to have broken actually looking at the existing $_SESSION:
public function provideSessionInfo(WebRequest $request)
{
// $_SESSION is hidden away per-request, but $request->getSession likes to call this function (yay infinite loops)
if (!isset($_SESSION['memberid'])) {
return null;
}
$memberid = $_SESSION['memberid'];
$mr_user = MyRadio_User::getInstance($memberid);
$user = User::newFromName($memberid);
$dbr = wfGetDB(DB_REPLICA);
$s = $dbr->selectRow('user', ['user_id'], ['user_name' => $memberid]);
if ($s === false) {
return null;
} else {
$user->mName = $memberid;
$user->mId = $user->idForName();
$user->loadFromDatabase();
$user->saveSettings();
}
if ($mr_user->hasAuth(AUTH_WIKIADMIN) && !in_array('sysop', $user->getGroups())) {
$user->addGroup('sysop');
}
$user->mTouched = wfTimestampnow();
return new SessionInfo(SessionInfo::MAX_PRIORITY, [
'provider' => $this,
'persisted' => true,
'userInfo' => UserInfo::newFromUser($user, true),
]);
}
If I hardcode $memberid, the function and the session provider works fine, but I just can't seem to find a way to transfer the session from one PHP "application" to another.
Adding debugging shows the PHPSESSID variable still set in the cookie, but for whatever reason it can't be pulled out into an actual session object. I've tried various session_start() style methods to no effect.
I feel like I'm missing something obvious, but the documentation for this stuff is just a basic wiki page and the raw generated doxygen.
Session handling is not a good way of cross-application communication. MediaWiki uses its own session handling, which means there is no connection between $_SESSION in MediaWiki and $_SESSION in your application at all. The first will be populated from MediaWiki's object cache (as configured by $wgSessionCacheType), the other from PHP session files or whatever.
If you really do not have a better way to pass data, you'll have to write a custom access class which can be called by your provider, which will save the current session handler, install a null session handler (which restores PHP's native session handling which will hopefully be interoperable with the other application), start the session, fetch the session data, restore the original session handler, and probably start the session again.
Currently I am trying to close session at the start of action, because this is an AJAX action, that does not need any session at all.
protected function _closeSession(Request $request)
{
if($request->hasSession()){
$session = $request->getSession();
$session->save();
}
}
public function listAction(Request $request, $mode, $id)
{
$data = [];
$this->_closeSession($request);
//perform long polling
//return json response
$response = new Response(json_encode($data));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
But I get this error from NativeSessionStorage: Failed to start the session because headers have already been send.
UPDATE:
The problem is that I have 2 separate ajax calls, one for adding comments to site, and another, long-running script that is shows those comments on page via trick called long-polling. But there is a problem, when second script is blocking the first, because both are using sessions by default. This problem is described here - Long running background PHP script blocks other PHP pages until it is finished . And I found a solution to call session_write_close manually instead of $session->save() in _closeSession. But are there any other, more Symfony-style ways to do that?
If you don't need authentication to those controllers, maybe this should be a workaround.
In security.yml (sf 3.4):
firewalls:
# disables session creation for assets controller
assets:
pattern: ^/assets
stateless: true
security: false
I'm trying to set a cookie when I load a view:
$cookie = Cookie::make('mycookie', $myval, 43200);
$view = view('myview')->with($data);
return Response::make($view)->withCookie($cookie);
And read the cookie on a later request:
if (Cookie::has('mycookie')) {
//do something
}
The cookie never gets set... where am I going wrong?
This works to reliably set a cookie with Laravel:
use Illuminate\Http\Request;
use Illuminate\Contracts\Cookie\Factory;
class MyClass
{
public function handle(Request $request, Factory $cookie)
{
$cookie->queue($cookie->make('myCookie', $request->someVal, 129600));
return redirect('/myPage');
}
}
You can create cookie like following
$view = view('myview')->with($data);
$response = new Illuminate\Http\Response($view);
return $response->withCookie(cookie('name', 'value', $minutes));
Or you can queue the cookie like below, and it will be sent with next request,
Cookie::queue('name', 'value');
return response('Hello World');
Read More
A possible cause of your missing cookie problem could be that if you have a invalid Blade directive the page will display normally however any cookies set will not be persisted.
I encountered this problem as I had included #script in my blade template rather than #section('script')
I suspect the reason the cookies does get set is that the bad directive causes an error in the compiled php code that the view gets cached as and so the processing crashes before the cookie is transferred.
I'm using Cakephp's build in test framework to test my controllers. I have a logout function that expires a variety of cookies that are created as the user uses the site. I am trying to read said cookies to determine if a test should pass or not, i.e. to test if the cookie is correctly expired. I have made sure that the cookie component is correctly instantiated, but I cannot read any value back from the cookie that should be there. This is the code that composes the test I am running:
public function testLogout() {
// setup the cookie component
$collection = new ComponentCollection();
$this->Cookie = new CookieComponent($collection);
$result = $this->testAction('/users/logout');
$cookie_name = Configure::read('tech_cookie_name');
$cookie_data = $this->Cookie->read($cookie_name);
debug($cookie_name);
// cookie data is returning as NULL but I'm expecting some type of value.
debug($cookie_data);
debug($result);
exit;
}
I realize that exit is killing the test early, but I'm using it to see if anything is send back from the cookie. I'm not sure why I cannot read any data from a cookie that I know is there. Does anyone know why that might be, or have a solution for how to properly read from cookies in a unit test.
You cann't read from routes.php Configure::read() in certain cases and it is not a good practice. it will work in localhost but not in live. try to configure your session properly.
by calling your session from AppController and also from your current Controller (UserController) then you should be able to see it in your testing actions.
public $components = array('Session', 'RequestHandler', 'Cookie', ...);
if you write your session like this:
$this->Session->write('Test.tech_cookie_name', 'tech_cookie_name');
then you should be able to read it like this:
$this->Session->read('Test.tech_cookie_name');