I have a JSF 2.0 application, let's call it "MyApp", with a SessionScoped bean that uses the below code to get the session and set the path on init...
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest(); //Get request from external context
HttpSession session = request.getSession(false); //Get session and don't create one if it doesn't exist
session.getServletContext().getSessionCookieConfig().setPath(""); //Set the path in the session's cookie
My problem is that the updated path ("") doesn't show up in the response session cookie, JSESSIONID, until the second request to the application. The first request gets a JSESSIONID cookie in the response with the default path, which includes the application's root context ("/MyApp"). If I reload the page, this second request will get a response with a JSESSIONID cookie that includes the updated path ("").
I can't seem to find any documentation on when the default JSESSIONID cookie is created and added to the response. I'm not sure if the updated session path is being set in the first response's JSESSIONID cookie or if it's being set and overridden by the page's default JSESSIONID cookie.
Questions:
When does the default JSESSIONID cookie get added to the response?
Is it possible to disable the page's default JSESSIONID cookie from being created?
When does the default JSESSIONID cookie get added to the response?
When the HTTP session is created for the first time. E.g. when JSF needs to put a newly created session scoped bean in there. So if you're writing some code in such a bean which should manipulate the session, then you're basically already too late.
Your code snippet is also a strong evidence for it. If the session was really not created, then request.getSession(false) would have returned null and subsequently, calling session.getServletContext() would have thrown a NullPointerException and you'd have asked a very different question.
Is it possible to disable the page's default JSESSIONID cookie from being created?
I believe you're asking the wrong question. You actually want to ask how to set the session cookie path the right way.
You're supposed to configure the session cookie path in web.xml as below:
<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>
If you really intend to do it programmatically for some unclear reason which is not elaborated in the question, then you should be doing this before the HTTP session is created for the first time. In other words, you should absolutely not be doing this in a session scoped JSF managed bean, nor be grabbing the needed ServletContext from the HttpSession itself.
Most sensible place would be a servlet context listener or, if you really need it to be "JSF-ish", then an eagerly initialized application scoped bean. Please note that this is an application-wide setting, not a session-wide setting. It being a property of ServletContext (and not of HttpSession) already hints that. Thus, once you set it, it affects all newly created session cookies. Depending on the concrete functional requirement which you told nothing about, there may be better ways. E.g. an additional cookie.
Related
Is there any good reason not to simply destroy the HTTP session like:
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(false);
session.invalidate();
instead of just deauthenticating the user and make sure to clean user data from the session scoped beans?
You have to do both. Deauthenticating the user can depend on your implementation. If you call out to a third party system to obtain a security token for a user, chances are you have to call back again to invalidate the token.
You also have to invalidate the HttpSession. Invalidating the session will release all session scoped beans. It also releases JSF view states and component trees for pages visited during the user's session. These can make the session sizeable and not invalidating will leave the heap full of sessions waiting to timeout and that have a negative impact on the server's capacity.
BTW, you can invalidate the session without the need to obtain the HttpSession, like so:
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
Find the answer in Oracle documentation:
The session.invalidate() method, which is often used to log out a
user, only invalidates the current session for a user—the user's
authentication information still remains valid and is stored in the
context of the server or virtual host. If the server or virtual host
is hosting only one Web application, the session.invalidate() method,
in effect, logs out the user.
http://docs.oracle.com/cd/E11035_01/wls100/webapp/sessions.html#wp150374
Currently, I am creating a web application for an online shopping cart and I need to maintain session on each jsf page..
My questions are :
How can I create and destroy session in managed bean
How can I access value stored in session variable? Like this?
FacesContext.getCurrentInstance().getExternalContext().getSessionMap.put("key",object);
How can I destroy a session in jsf
I also need to destroy the session using session.invalidate() but i am failed !!
How can I create and destroy session in managed bean
You don't need to create it yourself. The servletcontainer will do it automatically for you on demand. In other words, whenever you (or JSF) need to set an object in the session scope, then the servletcontainer will automatically create the session. In a JSF web application, this will happen when you
Reference a #SessionScoped or #ViewScoped managed bean for the first time.
Obtain the session by ExternalContext#getSession(), passing true for the first time.
Store an object in session map by ExternalContext#getSessionMap() for the first time.
Return a page with a <h:form> for the first time while the state saving method is set to "server".
You can destroy the session by ExternalContext#invalidateSession(). E.g.
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "login?faces-redirect=true";
}
Remember to send a redirect afterwards, because the session objects are still available in the response of the current request, but not anymore in the next request.
How can I access value stored in session variable?
Just make it a property of a #SessionScoped managed bean. Alternatively, you can also manually manipulate the ExternalContext#getSessionMap(), yes.
How can I destroy a session in jsf
This is already answered in the first question.
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading
Basic steps for starting session in jsf
How to choose the right bean scope?
I'm new to JSF and I was doing some research about Scopes and Http session lifecycles, but one thing was not clear to me.
I know that is possible to store variables using sessionMap from ExternalContext, and it used to work very fine for what I needed. I also know that when the session is invalidated all the data stored on the map is lost.
However, what I don't know is: when the page is refreshed the session is invalidated?
My problem appeared when I had to put a download request on one of the buttons from my web application. Apparently download requests cannot be made via Ajax, so the entire page have to be refreshed. The download proceed normaly, but after that, all the data stored on the map is gone, including all the managed beans. The user data itself is not that important as I can store it and then put it again on the new session map. But what about the managed beans? How should I proceed?
Assuming that it's not the webbrowser who misbehaved, this can only happen if the server side code is actually by itself invalidating the session by calling ExternalContext#invalidateSession() or HttpSession#invalidate().
If you can't seem to nail it down, then create a HttpSessionListener and put a debug breakpoint on sessionDestroyed() method and investigate the call stack who initiated it and why.
I am looking for the default codebase for creating jsessionids. It may vary from instance to instance, but I can't seem to find it on the net, just explanations of how to change/set it.
Thanks
JSESSIONID cookie is created/sent when session is created. Session is created when your code calls request.getSession() or request.getSession(true) for the first time. If you just want get session, but not create it if it doesn't exists, use request.getSession(false) -- this will return you a session or null. In this case, new session is not created, and JSESSIONID cookie is not sent. (This also means that session isn't necessarily created on first request... you and your code is in control when the session is created)
Sessions are per-context:
SRV.7.3 Session Scope
HttpSession objects must be scoped at the application (or servlet context) level. The underlying mechanism, such as the cookie used to establish the session, can be the same for different contexts, but the object referenced, including the attributes in that object, must never be shared between contexts by the container.
I'm working on a JSF 1.2 + RichFaces system. This system is a kind of blog. Users can create their blogs and manage them. Blogs are accessible by a url type this:
www.meublog.com/NameOfBlog
I used a single Managed Bean with session scope to make all controls. When the user accesses the blog, I use a filter that through the URL, which identified the blog being accessed, put the ID of the blog in the session and gave foward to the blog index.
I used this session ManagedBean to control everything in the view of the blog.
The problem is that the browser shares the same session between multiple tabs. When a user accesses the blog like this www.meublog.com/julio on one tab and www.meublog.com/fulano in another tab, I can not identify the two blogs because I have only one session established.
I wonder to know if anyone knows the correct path to follow here ...
You should not store request scoped information in the session scope for exactly the reasons you're facing. Use a request scoped managed bean instead which get initialized based on the request URI. You can get most of the request details by ExternalContext and/or HttpServletRequest.
E.g., inside bean's constructor or #PostConstruct method:
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
// If you use suffix mapping like *.jsf
String servletPath = ec.getRequestServletPath();
// Or if you use prefix mapping like /faces/*
String pathInfo = ec.getRequestPathInfo();
// Now initialize based on the value of either servletPath or pathInfo.
See also:
How to choose the right bean scope?