please note: Play Framework newbie
Intro
I need to use session() and/or response().cookies to pass data/store data.
At first session() started with this issue, now cookies are following along.
Problem:
Given a basic example code below, I have a boolean value setting a result, followed by cookies being created and added to the result.
Here on, the myPage is rendered, which contains a POST action to an action within the same controller, UserController
In this new method, there are no cookies. This is confirmed by
Collection<Http.Cookie> cookies = response().cookies();
with a size of 0
UserController
//...
Result result;
if(b)
result = ok(myPage.render());
else
result = new MyController().index();
result = result.withCookies(
new Http.Cookie("id", "value", 86400, "", "", true, false, Http.Cookie.SameSite.LAX),
new Http.Cookie("id_2", "value_2", 3600, "", "", true, false, Http.Cookie.SameSite.LAX)
);
return result;
//...
Question:
The documentation states that a session() lasts the entire duration while the browser window is open.
Cookies are stored client side and loaded when the webpage loads, session is regarded a bunch of cookies.
Why would setting session() entries or adding cookies() as shown above, be cleared, i.e. no cookies available in the response()?
What can I look for, what would remove session() or cookie entries?
Well there was no secret answer...
This is not shown in the question, but cookies name or id may contain no spaces. This was causing my problems. After removing the spaces in the name/id (values could have spaces),
then the issue was resolved
Related
I have SpringBoot 2.0.0.M7 project where I am using WebSession with Redis (org.springframework.session:spring-session-data-redis:2.0.0.RELEASE).
I have a WebFlux route which supposed to do redirect to eBay with the eBay session id. Every time user is visiting that route I need to request different session id from eBay API and include it into the redirect URL. Later, eBay will redirect user back to my application where I need that session id to request token.
During testing I saw that that value of the session attribute (in my case it's ebay_session_id) can't be replaced with the new value when browser still have a cookie with the existing session ID. In the route where I am requesting again ebay_session_id I am getting old value and not the new one.
The code which store SessionID is following:
return ebayApiReactiveWrapper
.getSessionId(apiContext)
.flatMap(sessionId ->
request
.session()
.map(webSession -> {
webSession
.getAttributes()
.put("ebay_session_id", sessionId);
return sessionId;
})
)
.flatMap(sessionId -> {
final UriBuilder uriBuilder = uriBuilderFactory.uriString(
ebayApiSettings.getSignInUrl()
);
uriBuilder.queryParam("runame", ebaySettings.getRuName());
uriBuilder.queryParam("SessID", sessionId);
return ServerResponse.temporaryRedirect(redirectUri).build();
});
I tried to add webSession.save() after put method but it doesn't help.
What I am doing wrong? Thank you in advance!
UPDATE
Some new details about what is happening with the session data in Redis. When session is created (empty Redis) the data looks like that:
127.0.0.1:6379> hkeys "spring:session:sessions:cbbf8000-6ce8-4238-a427-9aab37d2702b"
1) "lastAccessedTime"
2) "maxInactiveInterval"
3) "creationTime"
4) "sessionAttr:ebay_session_id"
When I visit same route second time (session cookie still exists and the session data is still in Redis) the data is changing:
127.0.0.1:6379> hkeys "spring:session:sessions:cbbf8000-6ce8-4238-a427-9aab37d2702b"
1) "sessionAttr:ebay_session_id"
Through, sessionAttr:ebay_session_id still contains value from the first request.
The worst thing is that such structure cause NullPointerException when another route is trying to get session data. Looks like it expecting other 3 fields to be presented and fails when it's not the case.
Looks like not many people faced such issue. I found my solution to solve it.
I saw that session will not be updated if the attribute set of the session is not changed. So I am adding a new attribute every time I need to update session value. My first flatMap from the question code is changed the following way:
.flatMap(sessionId ->
request
.session()
.map(webSession -> {
// we need to check if session already started before applying "hack"
if (webSession.isStarted()) {
// "hack"
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yMdkmsn");
webSession
.getAttributes()
.put(LocalDateTime.now().format(dateTimeFormatter),"1");
}
webSession
.getAttributes()
.put("ebay_session_id", sessionId);
return sessionId;
})
)
When new attribute is added session considered as changed and will be updated in redis.
I faced that problem and used almost the same hack, but just by updating a primitive typed session attribute.
For example:
webSession.getAttributes().put("userContext", userContext);
webSession.getAttributes().put("lastContextUpdateTime", System.currentTimeMillis());
This avoids to add a new attribute for each session update, but triggers the mutable object update in Redis too.
Hello guys I want to make the remember me checkbox and I want to save the user info into cookies so next time when try to login he find the user name and password in their fields I try to use :
$rememberMe = false;
if(isset($req->remember_me)) {
$rememberMe = true;
}
if(Sentinel::authenticate($req->all(), $rememberMe)) {
$slug = Sentinel::getUser()->roles()->first()->slug();
}
The cookies was set, I see it in the chrome settings but it does not do as I expect
I'm using laravel 5.2
You can use Cookies
cookie, is a small piece of data sent from a website and stored in a user's web browser while the user is browsing that website. Every time the user loads the website, the browser sends the cookie back to the server to notify the website of the user's previous activity
To create:
$response->withCookie(Cookie::make('name', 'value', $minutes));
To retrieve
$value = Cookie::get('name');
Your question is not to remember the user login.. The question is how to fill the inputs based on saved auth information. You can do that if you print the authentication values in the input value attribute while loading the page.
larval Cookies Docs
Also Laravel has it's own implementation of "Remember Me"
if (Auth::attempt(array('email' => $email, 'password' => $password), true))
{
// The user is being remembered...
}
if (Auth::viaRemember())
{
//
}
More information about https://laravel.com/docs/5.4/authentication#remembering-users
There is two main thing need to taken care:
1) You must pass a bool value as second parameter to the method, make sure you cast it before passing it to the method. - In your code, it's perfect
$credentials = $req->only('LOGINNAME', 'PASSNAME')
if(Sentinel::authenticate($credentials , $req->has('remember_me'))){
//Other stuff
}
2) you can verify it works by ensuring a cookie is set with the key cartalyst_sentinel?
So first change as per 1) option and then check the 2) option, may be this is your answer.
I am building and extension with Firefox's Addon SDK (v1.9).
My application is supposed to remove cookies as they are added (or changed) based on a database of matching URIs.
I accomplish this task by adding an observer to 'cookie-changed' and implementing nsICookie to identify matching cookies and nsICookieManager to remove the cookie if a match is found.
Problem
I need know what website (URL) each cookie was added / changed from.
Unfortunately, by the time the cookie manager sends the cookie-changed notification that information is already lost - the cookie manager only knows which host the cookie is added for (and it might not be the host of the page setting the cookie if domain parameter was used). It might even be that there was no URL in the first place, e.g. if the cookie is set by an extension.
What you could do is register an observer for the http-on-examine-response notification. You can look at the Set-Cookie header of the channel as well as the channel URL so when cookie-changed notification is sent later you will know which website is responsible. Something like this:
var observer = require("observer-service");
observer.add("http-on-examine-response", function(subject, data)
{
subject.QueryInterface(Ci.nsIHttpChannel);
var cookieNames = [];
// There can be more than one Set-Cookie header, cannot use getResponseHeader
subject.visitResponseHeaders(function(header, value)
{
if (header.toLowerCase() == "set-cookie")
{
var match = /^([^\s=]+)=/.exec(value);
if (match)
cookieNames.push(match[1]);
}
});
if (cookieNames.length)
{
var url = channel.URI.spec;
// Remember that this url set the cookies or just clear the header
if (!isAllowedToSetCookies(url, cookieNames))
channel.setResponseHeader("Set-Cookie", "", false);
}
});
Note: This code hasn't been tested.
Documentation: observer notifications, nsIHttpChannel
I would like to execute the below line when the user logs in so that I have access to the MembershipUser object. However I am having a hard time figuring out when to set it.
Session["User"] = Membership.GetUser();
So far I've tried...
Application_AcquireRequestState
Application_BeginRequest
FormsAuthentication_OnAuthenticate
For each the session state isn't necessarily available.
Manually calling it in the log-in page is easy, but I need to have it work when automatically logging in using cookies as well.
If all you want do is store arbitrary data along with the username, there is an open source project called FormsAuthenticationExtensions that allows you to do exactly this in a very simple manner:
In your Login action you would store your data like this:
var ticketData = new NameValueCollection
{
{ "name", user.FullName },
{ "emailAddress", user.EmailAddress }
};
new FormsAuthentication().SetAuthCookie(user.UserId, true, ticketData);
And you read it back like this:
var ticketData = ((FormsIdentity) User.Identity).Ticket.GetStructuredUserData();
var name = ticketData["name"];
var emailAddress = ticketData["emailAddress"];
Data is stored in the same cookie holding the authentication ticket, so it will be available for as long as the user is logged in.
Project page: http://formsauthext.codeplex.com/
Nuget: http://nuget.org/List/Packages/FormsAuthenticationExtensions
Why? You can access Membership.GetUser from anywhere. It's a static method. What is the point of placing a value you can access from anywhere in a place you can access from anywhere?
I feel like this has to be buried somewhere in the documentation, but I can't find it.
How do you close or end or kill (whatever) a session in ExpressJS?
Express 4.x Updated Answer
Session handling is no longer built into Express. This answer refers to the standard session module: https://github.com/expressjs/session
To clear the session data, simply use:
req.session.destroy();
The documentation is a bit useless on this. It says:
Destroys the session, removing req.session, will be re-generated next request.
req.session.destroy(function(err) {
// cannot access session here
})
This does not mean that the current session will be re-loaded on the next request. It means that a clean empty session will be created in your session store on next request. (Presumably the session ID isn't changing, but I have not tested that.)
Never mind, it's req.session.destroy();
The question didn't clarify what type of session store was being used. Both answers seem to be correct.
For cookie based sessions:
From http://expressjs.com/api.html#cookieSession
req.session = null // Deletes the cookie.
For Redis, etc based sessions:
req.session.destroy // Deletes the session in the database.
Session.destroy(callback)
Destroys the session and will unset the req.session property. Once complete, the callback will be invoked.
↓ Secure way ↓ ✅
req.session.destroy((err) => {
res.redirect('/') // will always fire after session is destroyed
})
↓ Unsecure way ↓ ❌
req.logout();
res.redirect('/') // can be called before logout is done
use,
delete req.session.yoursessionname;
From http://expressjs.com/api.html#cookieSession
To clear a cookie simply assign the session to null before responding:
req.session = null
To end a server-side session
https://github.com/expressjs/session#sessiondestroycallback
req.session.destroy(function(err) {
// cannot access session here
})
Note, this is essentially a wrapper around delete req.session as seen in the source code:
https://github.com/expressjs/session/blob/master/session/session.js
defineMethod(Session.prototype, 'destroy', function destroy(fn) {
delete this.req.session;
this.req.sessionStore.destroy(this.id, fn);
return this;
});
To end a cookie-session
https://github.com/expressjs/cookie-session#destroying-a-session
req.session = null;
req.session.destroy();
The above did not work for me so I did this.
req.session.cookie.expires = new Date().getTime();
By setting the expiration of the cookie to the current time, the session expired on its own.
You can retrieve the id of a session using req.session.id or req.sessionID and then pass it to req.sessionStore.destroy method like so:
const sessionID = req.session.id;
req.sessionStore.destroy(sessionID, (err) => {
// callback function. If an error occurs, it will be accessible here.
if(err){
return console.error(err)
}
console.log("The session has been destroyed!")
})
Reference to the req.sessionStore.destroy method.
As mentioned in several places, I'm also not able to get the req.session.destroy() function to work correctly.
This is my work around .. seems to do the trick, and still allows req.flash to be used
req.session = {};
If you delete or set req.session = null; , seems then you can't use req.flash