问题
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?
回答1:
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 tofalse
.
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);
}
}
回答2:
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.
来源:https://stackoverflow.com/questions/9219393/invalidate-session-of-a-specific-user