In my application I have a quit button, on clicking of which the session for the current user is invalidated by the following piece of the code..
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
And I redirect the user to a different page.
But now I want if user click on the back button I will take him to the start page of the application instead of the last page visted by him.
I have an application phase listener which sets the page cache related headers to 'none', now all I want is to detect that for that user session has been invalidated.
But I guess whenever the user is clicking the back button it is creating a new session for the user. Is there any way to prevent it?
How to detect session has been invalidated in JSF 2?
Check if the user has requested a session ID which is not valid.
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
// Session has been invalidated during the previous request.
}
it is creating a new session for the user. Is there any way to prevent it?
Just don't let your application code create the session then. The session will implicitly be created when your application needs to store something in the session, e.g. view or session scoped beans, or the view state of a <h:form>, etc.
I have an application phase listener which sets the page cache related headers to 'none'
A servlet filter is a better place for this. See also Avoid back button on JSF web application
Related
I tried to save an id and a name in a JSF Session but they are not being stored.
When I refresh the page it disappears.
This is the code I'm using:
HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
session.setAttribute("id", 123);
session.setAttribute("name", "a name");
what i want to do by session is securing my pages using a Filter and inside it im testing if the session existe or not
Please help me
Regards
I solved my problem :D
I had a session scoped ManagedBean that was disappearing when the page was refreshed. So the problem is that the session was expiring after 1s or less. So I set the setSessionMaxInactiveInterval to -1 which disables the session expiration timeout:
FacesContext.getCurrentInstance()
.getExternalContext()
.setSessionMaxInactiveInterval(-1);
In our Java EE application we use container based certificate authentication. We have created JAASLoginModule, which implements LoginModule interface with all required methods. We have configured our Wildfly and TomEE server to use this module both for authentication and ssl channel security, and everything goes smoothly with user login:
the user opens the browser and the app;
selects a certificate;
a JSF session is created, and now he is logged in;
A different story is with the logout. Just destroying the JSF session is not enough - after logout, if you just click back, the browser will get the certificate info from cache, recreate a session and lets you do the same stuff. Sometimes even browser restart does not help.
I could not find an effective way to call the logout method from the LoginModule from the JSF managed bean.
Any way to solve this problem?
Your problem is directly with the browser, so what you need is to tell the browser to "restart" the cache from your page every time it logs out, this, in order for it to think it's the first time the client is trying to get into that page. Kind of the same that private windows in Chrome and Firefox do.
Try this code:
//...
response.setHeader("Cache-Control","no-cache"); //Forces caches to obtain a new copy of the page from the origin server
response.setHeader("Cache-Control","no-store"); //Directs caches not to store the page under any circumstance
response.setDateHeader("Expires", 0); //Causes the proxy cache to see the page as "stale"
response.setHeader("Pragma","no-cache"); //HTTP 1.0 backward compatibility
//can check userId or something likes this.In this sample, i checked with userName.
String userName = (String) session.getAttribute("User");
if (null == userName) {
request.setAttribute("Error", "Session has ended. Please login.");
RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
rd.forward(request, response);
}
Source: How to clear browser cache using java
I am new to servlet filter.
I am using JSF 2.2, Wildfly 8.1. I have figured out that if user clicks log out link when session is already expired then when user logs in again the system will continiously fire exception of session expired. BalusC wrote to write servlet filter which will delete all cookies of specific domain before user will see welcome page.
How to write servlet filter which will destroy all cookies related to specific domain (domain.com) when new session will start? I played with it and absolutely confused. sorry for my a little experience in jsf.
I think you need to set cookie.setMaxAge(0);for all the cookie for that domain.
Inside your filter(which should be used for Logout request only) or in Logout servlet(if any) you can write below line to delete all cookie.
Cookie[] cookies = req.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
cookie.setValue("");
cookie.setPath("/");
cookie.setMaxAge(0);
resp.addCookie(cookie)
}
}
So I'm having a problem trying to pass a String value.
The String value is entered through a login page as username.
The JSF then calls the Bean to verify log in information then proceeds to another JSF page.
I was wondering how to pass the username along to the new JSF page. Thank you.
If you're performing a navigation instead of a redirect, then you basically don't need to do anything. The information is also just available in the navigated page.
E.g. in login page,
<h:inputText value="#{bean.username}" />
and in the navigated page:
<p>You have entered the following username: #{bean.username}</p>
If you're however performing a redirect instead of a navigation, then you basically need to store the information in a bit broader scope. You didn't clearly elaborate the concrete functional requirement in the question, but if I guess it right, you just wanted to remember the currently logged-in user for the remaining of the HTTP session. In that case, just store it in the session scope during the login action.
public String login() {
// ...
User user = userService.find(username, password);
// ...
externalContext.getSessionMap().put("user", user);
// ...
return "nextpage?faces-redirect=true";
}
This way it's available by #{user} throughout the entire HTTP session.
<p>You're logged in as #{user.name}.</p>
You can also use <t:saveState> without using session scope. <t:saveState> is longer than the request scope but shorter than session scope.
This may help you : http://myfaces.apache.org/tomahawk-project/tomahawk12/tagdoc/t_saveState.html
So for my webapp, if I remove a user that is currently logged in, and I want to invalidate his/her session. So that as soon as he/she refresh the page or navigate, they are no longer log in. The way I have now is that if a User logged in successfully, I will store the user object in my SessionScoped bean, and store the HttpSession to the Application Map. Below is my code
This is my SessionScoped bean
#PostConstruct
public void init() {
User user = UserDAO.findById(userId, password);
Map<String, Object> appMap = FacesContext.getCurrentInstance().
getExternalContext().getApplicationMap();
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().
getExternalContext().getSession(false);
appMap.put(userId, session);
}
Is this a correct approach? If so, how do I clean up my application map?
Is this a correct approach?
There are basically 2 ways.
Store the HttpSession handle in the application scope by the user ID as key so that you can get a handle of it and invalidate it. This may work for a small web application running on a single server, but may not work on a web application running on a cluster of servers, depending on its configuration.
I would only store it in another map in the application scope, not directly in the application scope like as you did, so that you can easier get an overview of all users and that you can guarantee that an arbitrary user ID won't clash with an existing application scoped managed bean name, for example.
Add a new boolean/bit column to some DB table associated with the user which is checked on every HTTP request. If the admin sets it to true, then the session associated with the request will be invalidated and the value in the DB will be set back to false.
how do I clean up my application map?
You could use HttpSessionListener#sessionDestroyed() for this. E.g.
public void sessionDestroyed(HttpSessionEvent event) {
User user = (User) event.getSession().getAttribute("user");
if (user != null) {
Map<User, HttpSession> logins = (Map<User, HttpSession>) event.getSession().getServletContext().getAttribute("logins");
logins.remove(user);
}
}
I think you can use your approach (with some modifications proposed by #BalusC) plus some notification mechanism (to make it work in distributed environment). You can do one of the following:
Use a topic queue subscribed by all your servers. When you remove user from your admin panel the JMS message will be created and sent to the topic. Every server will be responsible for invalidating the user session if it exists on the particular server (if the session is referenced in servletContext map).
Implement some action to invalidate the user session and run this action on every server in the cluster (The admin panel should send HTTP request to every server).
Use JGroups and TCP reliable multicast.
All of these solutions are not simple but much faster than polling the DB server on every request.