JSF HTTP Session Login - jsf

I try to create login form in web application.
in JSP page I can use
<%
String name = request.getParameter( "username" );
session.setAttribute( "theName", name );
%>
but now I am using JSF /Facelets for web application
I don't know how to create session in JSF Backing bean for client and check if user is logged in or not so it will redirect into login page.
who can help me give me link tutorial for these problem ?
thank you before
Now I have little problem with mapping into web.xml
code snipped of class Filter
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
LoginController controller = (LoginController) req.getSession()
.getAttribute("loginController");
if (controller == null || !controller.isLoggedIn()) {
res.sendRedirect("../admin/login.xhtml");
} else {
chain.doFilter(request, response);
}
}
and in web.xml I map with <fitler> tag
<filter>
<filter-name>userLoginFilter</filter-name>
<filter-class>com.mcgraw.controller.UserLoginFilter</filter-class>
<init-param>
<param-name>loginPage</param-name>
<param-value>/login.xhtml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>userLoginFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
I have one folder admin in web project and I check if the user is not logged in with admin permission to not access page (I can do the permission check) but when I use the filter the browser doesn't understand url ??
no StackTrace show when the browser doesn't understand url
Error shown on Firefox
The page isn't redirecting properly
on IE it loading ... loading . .. non-stop
now I change condition which check if req.getPathInfo.startsWith("/login.xhtml") it will do chain
I have 2 idea but it response 500 HTTP STATUS
if (controller == null || !controller.isLoggedIn()) {
res.sendRedirect("../admin/login.xhtml");
if(req.getPathInfo().startsWith("/login.xhtml")){
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
===============
if (controller == null || !controller.isLoggedIn()) {
if (!req.getPathInfo().startsWith("/login.xhtml")) {
res.sendRedirect("../admin/login.xhtml");
} else {
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
======================
update Class loginController
package com.mcgraw.controller;
import com.DAO.UserBean;
import com.entity.IUser;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
/**
* #author Kency
*/
#ManagedBean
#SessionScoped
public class LoginController implements Serializable {
#EJB
private UserBean userBean;
private IUser user;
private boolean admin;
private boolean mod;
private PasswordService md5;
/** Creates a new instance of LoginController */
public LoginController() {
user = new IUser();
md5 = new PasswordService();
}
// getter / setter
public boolean isMod() {
return mod;
}
public void setMod(boolean mod) {
this.mod = mod;
}
public IUser getUser() {
return user;
}
public void setUser(IUser user) {
this.user = user;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public String cplogin() {
String md5Password = md5.md5Password(user.getPassword());
if (userBean.userLogin(user.getUsername(), md5Password) != null) {
if (user.getUsername() != null || md5Password != null) {
user = userBean.userLogin(user.getUsername(), md5Password);
if (user.getGroups().getAdmin() != null) {
setAdmin(user.getGroups().getAdmin());
}
if (user.getGroups().getMods() != null) {
setMod(user.getGroups().getMods());
}
if (isAdmin() == true || isMod() == true) {
return "home";
} else {
return "login";
}
} else {
return "login";
}
} else {
return "login";
}
}
public String logout() {
user = null;
return "login";
}
public boolean isLoggedIn() {
return user != null;
}
}
I have new problem if render JSF taglib with method loggedIn, in index page (not in admin folder) user doesn't login can see what I render example, <== this like if user doesn't login user can't see but why can he see it?

You can in JSF get/set HTTP session attributes via ExternalContext#getSessionMap() which is basically a wrapper around HttpSession#get/setAttribute().
#Named
#RequestScoped
public class LoginController {
private String username;
private String password;
#EJB
private UserService userService;
public String login() {
User user = userService.find(username, password);
FacesContext context = FacesContext.getCurrentInstance();
if (user == null) {
context.addMessage(null, new FacesMessage("Unknown login, try again"));
username = null;
password = null;
return null;
} else {
context.getExternalContext().getSessionMap().put("user", user);
return "userhome?faces-redirect=true";
}
}
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "index?faces-redirect=true";
}
// ...
}
In the Facelets page, just bind the username and password input fields to this bean and invoke login() action accordingly.
<h:form>
<h:inputText value="#{loginController.username}" />
<h:inputSecret value="#{loginController.password}" />
<h:commandButton value="login" action="#{loginController.login}" />
</h:form>
Session attributes are directly accessible in EL. A session attribute with name user is in EL available as #{user}. When testing if the user is logged in some rendered attribute, just check if it's empty or not.
<h:panelGroup rendered="#{not empty user}">
<p>Welcome, #{user.fullName}</p>
<h:form>
<h:commandButton value="logout" action="#{loginController.logout}" />
</h:form>
</h:panelGroup>
The logout action basically just trashes the session.
As to checking an incoming request if a user is logged in or not, just create a Filter which does roughly the following in doFilter() method:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURI = request.getContextPath() + "/login.xhtml";
boolean loggedIn = session != null && session.getAttribute("user") != null;
boolean loginRequest = request.getRequestURI().equals(loginURI);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);
if (loggedIn || loginRequest || resourceRequest) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURI);
}
}
Map it on an url-pattern covering the restricted pages, e.g. /secured/*, /app/*, etc.
See also:
How to handle authentication/authorization with users in a database?
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same

Try this in your backing bean when a request is received (like in an action method):
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpSession session = request.getSession();
Then you can work with the request and session objects just like you used to with JSPs, setting attributes and so on.
You might also want to take a look at my related question about checking the client session in a servlet Filter. You could write a similar Filter to check for the user login in their HttpSession and then do a redirect (or RequestDispatch like I ended up doing) to your login page if needed.

Related

JSF <protected-views> token inconsistency

I'm currently having trouble regarding the token generated by <protected-views> of JSF.
I added the page I want to protect in faces-config.xml
<protected-views>
<url-pattern>/restricted/account-management/users.xhtml</url-pattern>
<url-pattern>/restricted/account-management/users.jsf</url-pattern>
</protected-views>
Then for example when I go the users page using an <h:link>
<h:link outcome="users" title="View">
<f:param name="user" value="#{e.id}" />
</h:link>
the token generated in the URL is this
/restricted/account-management/users.jsf?javax.faces.Token=OW5KkkfJZrrfmZSXwA%253D%253D&user=4
The page returns a ProtectedViewException
Then I found out that the correct token is actually:
/restricted/account-management/users.jsf?javax.faces.Token=OW5KkkfJZrrfmZSXwA%3D%3D
The token was encoded in the URL, where % became %25. When I copy-paste the correct token into the URL, I get into the users page successfully.
Any help would be appreciated.
This is a problem with the versions 2.2.11 and above of Mojarra JSF Implementation, you can see the details about issue in https://github.com/javaee/javaserverfaces-spec/issues/1161 and here https://github.com/javaserverfaces/mojarra/issues/4139
One of the alternatives to handle the problem is to create a CustomExternalContext to handle the double encoding.
First you need declare in faces-config.xml a CustomExternalContextFactory:
<factory>
<external-context-factory>com.proitc.config.CustomExternalContextFactory</external-context-factory>
</factory>
In the ExternalContextFactory you define the CustomExternalContext:
public class CustomExternalContextFactory extends ExternalContextFactory {
private ExternalContextFactory externalContextFactory;
public CustomExternalContextFactory() {}
public CustomExternalContextFactory(ExternalContextFactory externalContextFactory) {
this.externalContextFactory = externalContextFactory;
}
#Override
public ExternalContext getExternalContext(Object context, Object request, Object response)
throws FacesException {
ExternalContext handler = new CustomExternalContext((ServletContext) context,
(HttpServletRequest) request, (HttpServletResponse) response);
return handler;
}
}
The CustomExternalContext override the methods encodeBookmarkableURL and encodeRedirectURL:
public class CustomExternalContext extends ExternalContextImpl {
public CustomExternalContext(ServletContext sc, ServletRequest request,
ServletResponse response) {
super(sc, request, response);
}
#Override
public String encodeBookmarkableURL(String baseUrl, Map<String, List<String>> parameters) {
FacesContext context = FacesContext.getCurrentInstance();
String encodingFromContext =
(String) context.getAttributes().get(RIConstants.FACELETS_ENCODING_KEY);
if (null == encodingFromContext) {
encodingFromContext =
(String) context.getViewRoot().getAttributes().get(RIConstants.FACELETS_ENCODING_KEY);
}
String currentResponseEncoding =
(null != encodingFromContext) ? encodingFromContext : getResponseCharacterEncoding();
UrlBuilder builder = new UrlBuilder(baseUrl, currentResponseEncoding);
builder.addParameters(parameters);
String secureUrl = builder.createUrl();
//Handle double encoding
if (parameters.size() > 0 && baseUrl.contains("javax.faces.Token")) {
try {
int beginToken = secureUrl.indexOf("javax.faces.Token");
int endToken = secureUrl.indexOf("&") - 1;
String doubleEncodeToken = secureUrl.substring(beginToken, endToken);
String encodeToken = URLDecoder.decode(doubleEncodeToken, currentResponseEncoding);
secureUrl = secureUrl.replace(doubleEncodeToken, encodeToken);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return secureUrl;
}
#Override
public String encodeRedirectURL(String baseUrl, Map<String, List<String>> parameters) {
FacesContext context = FacesContext.getCurrentInstance();
String encodingFromContext =
(String) context.getAttributes().get(RIConstants.FACELETS_ENCODING_KEY);
if (null == encodingFromContext) {
encodingFromContext =
(String) context.getViewRoot().getAttributes().get(RIConstants.FACELETS_ENCODING_KEY);
}
String currentResponseEncoding =
(null != encodingFromContext) ? encodingFromContext : getResponseCharacterEncoding();
UrlBuilder builder = new UrlBuilder(baseUrl, currentResponseEncoding);
builder.addParameters(parameters);
String secureUrl = builder.createUrl();
//Handle double encoding
if (parameters.size() > 0 && baseUrl.contains("javax.faces.Token")) {
try {
int beginToken = secureUrl.indexOf("javax.faces.Token");
int endToken = secureUrl.indexOf("&") - 1;
String doubleEncodeToken = secureUrl.substring(beginToken, endToken);
String encodeToken = URLDecoder.decode(doubleEncodeToken, currentResponseEncoding);
secureUrl = secureUrl.replace(doubleEncodeToken, encodeToken);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return secureUrl;
}
}
You can find a working example in https://github.com/earth001/jsf-protected-view

How can I integrate SSO authentication with JSF?

I'm currently using a Filter to check for SSO authentication. (SSO is considered authenticated if the request header contains the variable "Proxy-Remote-User").
if (!(isSsoLoggedIn(request)) {
response.sendRedirect(ERROR_PAGE);
return;
} else {
chain.doFilter(req, res);
}
private boolean isSsoLoggedIn(HttpServletRequest request) {
return request != null && request.getHeader("Proxy-Remote-User") != null
&& !request.getHeader("Proxy-Remote-User").equals("");
}
Now, once the user is authenticated, I want to pass that variable (which is an email address) to JSF. I do that with a session-scoped bean:
#PostConstruct
public void init {
Map<String, String> requestHeaderMap = FacesContext.getCurrentInstance().getExternalContext().getRequestHeaderMap();
String email = requestHeaderMap.get("Proxy-Remote-User");
user = getPersonFromDB(email);
}
This seems simple enough, but I'm not sure if its the "right" way to do this. It doesn't seem correct to rely on a bean's instantiation to verify authentication.
One idea I just had: Use a CDI session-scoped bean and #Inject it into the Filter. Then, you could have the filter itself check for a valid user and, if valid, set it in the session-scoped bean, otherwise forward it to an error page.
Does that sound like a valid solution?
Another approach could be to have every page check for authentication, before the view is rendered, with a view param as mentioned here:
JSF calls methods when managed bean constructor sends 404 ERROR CODE
<f:metadata>
<f:viewAction action="#{bean.checkForValidUser}" />
</f:metadata>
The only problem I have for this is...this would require copying/pasting the same code to every page which seems redundant (or at least a template for them all to use).
Here is the answer I came up with (thanks to some tips from #BalusC).
I check to see if developer login is enabled or SSO has been authenticated. Once I have the email address, I see if its a valid user, verify the JSF session contains the right user, and, if so, forward them on their way.
/**
* This filter handles SSO login (or developer login) privileges to the web
* application.
*/
#WebFilter(servletNames = "Faces Servlet")
public class SecurityFilter implements Filter {
#Inject
private SessionManager sessionManager;
#EJB
private PersonWriteFacadeRemote personFacade;
private HttpServletRequest currentRequest;
private HttpServletResponse currentResponse;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
currentRequest = (HttpServletRequest) req;
currentResponse = (HttpServletResponse) res;
HttpSession session = currentRequest.getSession();
String requestedPage = currentRequest.getRequestURI();
// check if the session is initialized
// if not, initialize it
if (!isSessionInitialized()) {
Person user = getCurrentUser();
// if we can't figure out who the user is, then send 401 error
if (user != null) {
initializeSession(user);
} else {
currentResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// if it is initialized, check if it actually matches the current
// user
// if not, invalidate the session and redirect them back to the page
// to reinitialize it
} else if (!isSessionCurrentUsers()) {
session.invalidate();
currentResponse.sendRedirect(requestedPage);
return;
}
chain.doFilter(req, res); // If all looks good, continue the request
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
private Person getCurrentUser() {
try {
return personFacade.createFromEmail(getUserEmail());
} catch (InvalidAttributesException ex) {
Logger.getLogger(SecurityFilter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
private String getUserEmail() {
return isDevLoginEnabled() ? getUserEmailFromJndi() : getUserEmailFromSso();
}
private String getUserEmailFromJndi() {
return JNDI.lookup("devLoginEmail");
}
private String getUserEmailFromSso() {
return currentRequest != null && currentRequest.getHeader("Proxy-Remote-User") != null
&& !currentRequest.getHeader("Proxy-Remote-User").equals("")
? currentRequest.getHeader("Proxy-Remote-User") : null;
}
private boolean isDevLoginEnabled() {
Boolean devLoginEnabled = JNDI.lookup("devLoginEnabled");
return (devLoginEnabled != null ? devLoginEnabled : false);
}
private boolean isSessionInitialized() {
return sessionManager.getUser() != null;
}
private void initializeSession(Person user) {
sessionManager.initializeSession(user);
}
private boolean isSessionCurrentUsers() {
return sessionManager.getUser() != null && sessionManager.getUser().getEmail() != null
&& sessionManager.getUser().getEmail().equals(getUserEmail());
}
}

JSF login filter, session is null

I've been trying to follow this answer primarily but I always get redirected to my login.xhtml (except for when i log in from the login page) because this...
AppManager am = (AppManager) req.getSession().getAttribute("appManager");
Is always null.
I've been trying to print out user info on the login screen and no matter how i get there all fields(username, password, loggedIn...) are always null, even if i type the adress straight from the admin page (that's where you get when you log in).
How do I make it so that the session is saved, not whiped everytime i type in the adress manually/leave the page?
AppManager:
import java.io.Serializable;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import jobapp.controller.Controller;
#ManagedBean(name="appManager")
#SessionScoped
public class AppManager implements Serializable {
private static final long serialVersionUID = 16247164405L;
#EJB
private Controller controller;
private String username;
private String password;
private boolean loggedIn;
private Exception failure;
...
/**
*
* #param e an exception to handle.
*/
private void handleException(Exception e) {
e.printStackTrace(System.err);
failure = e;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
/**
* The login method.
* calls the controllers login method.
*
*/
public void login(){
try{
failure = null;
loggedIn = controller.login(username, password);
}catch (Exception e){
handleException(e);
}
}
/**
* The logout method.
* Sets the user's info to null
* and stops the conversation.
*/
public void logout(){
username = null;
password = null;
loggedIn = false;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
...
Filter:
#WebFilter("/faces/admin.xhtml")
public class LoginFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//TODO fix "am" nullpointer
AppManager am = (AppManager) req.getSession().getAttribute("appManager");
if (am != null && am.isLoggedIn()) {
// User is logged in, so just continue request.
chain.doFilter(request, response);
} else {
// User is not logged in, so redirect to login.
HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect(req.getContextPath() + "/faces/login.xhtml");
}
}
#SessionScoped is from javax.enterprise.context.SessionScoped
This one works in combination with CDI #Named only. As you're using JSF #ManagedBean, you should be using the scope annotations from javax.faces.bean package instead.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class AppManager implements Serializable {
Without a valid scope, a JSF managed bean would behave like #RequestScoped which effectively means that it's constructed again and again on every request.

Prevent users to manually access to page

i have implemented jsf phase listener which check if user looged in or not, and if not redirect user to login page.
Now, i want to implement phase listener in case where user manualy input
page name in address bar. In this case phase listener must automatic
redirect user to login page and destroy session.
How do that in JSF ?
Just use a simple servlet Filter which is mapped on a common URL pattern of the restricted pages like /app/*, /pages/*, /secured/*, etc. Here's a kickoff example assuming that you've a #SessionScoped #ManagedBean UserManager.
#WebFilter(urlPatterns={"/app/*"})
public class AuthenticationFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
UserManager userManager = (session != null) ? (UserManager) session.getAttribute("userManager") : null;
if (userManager == null || !userManager.isLoggedIn()) {
response.sendRedirect(request.getContextPath() + "/login.xhtml"); // No logged-in user found, so redirect to login page.
} else {
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
// ...
}
I am on JSF 1.2 and did that this way:
public void beforePhase(PhaseEvent event)
{
FacesContext fCtx = FacesContext.getCurrentInstance();
String actualView = null;
actualView = event.getFacesContext().getApplication().getViewHandler().getResourceURL(fCtx, fCtx.getViewRoot().getViewId());
//actualView is the page the user wants to see
//you can check, if the user got the permission, is logged in, whatever
}
public PhaseId getPhaseId()
{
return PhaseId.RENDER_RESPONSE;
}

How to get number of connected users and their role using j_security_check?

I get the username of the connected user (using j_security_check) this way, through a managed bean:
......
username = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal().getName();
And then display it in a jsf page this way : #{userBean.username}
But I figured no way to get the number of connected users and get their role.
In other words, I want to display besides the username, the user role and the number of connected users.
How can I achieve this!?
Thanks in advance for your help!
EDIT:
I can now get the Role of the connected user, using a namedquery in a managed bean :
public Users getUserRole(){
try {
Users auser = (Users)
em.createNamedQuery("Users.findByUsername").
setParameter("username", getRemoteUser()).getSingleResult();
return auser;
} catch (NoResultException nre) {
JsfUtil.addErrorMessage(nre, "getUserRole Error");
return null;
}
}
and in the xhtml page:
<h:outputLabel for="rolefacet" value="Role: "/>
<h:outputFormat id="rolefacet" value="#{UserBean.userRole.ugroup}" />
while ugroup is the role name in the Users entity class.
EDIT: One solution that still does not work for me is to add a HttpSessionListener to my web.xml:
package beans;
/**
*
* #author med81
*/
import java.io.Serializable;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.ArrayList;
import javax.faces.context.FacesContext;
public class SessionCounter implements Serializable, HttpSessionListener {
private List sessions = new ArrayList();
Object s = FacesContext.getCurrentInstance().getExternalContext().getSession(false);
public Object getS() {
return s;
}
public void setS(Object s) {
this.s = s;
}
public SessionCounter() {
}
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
sessions.add(session.getId());
session.setAttribute("counter", this);
}
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
sessions.remove(session.getId());
session.setAttribute("counter", this);
}
/**
*
* #return size of the session list
*/
public int getActiveSessionNumber() {
return sessions.size();
}
}
Here's a basic kickoff example how you could do it when you're on Servlet 3.0 and thus are able to utilize programmatic login by the new HttpServletRequest#login() API.
The login form: login.xhtml
<h:form>
<h:inputText value="#{user.username}" />
<h:inputSecret value="#{user.password}" />
<h:commandButton value="Login" action="#{user.login}" />
<h:messages />
</h:form>
The user manager bean: com.example.UserManager
#ManagedBean(name="user")
#SessionScoped
public class UserManager implements Serializable {
private String username;
private String password;
private User current;
#EJB
private UserService userService;
#ManagedProperty("#{loginManager.logins}")
private Set<User> logins;
public String login() {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try {
request.login(username, password);
current = userService.find(username, password);
} catch (ServletException e) {
// Unknown login. Will be handled later in current==null check.
}
if (current == null) {
context.addMessage(null, new FacesMessage("Unknown login"));
return null;
} else {
logins.add(current)
return "home?faces-redirect=true";
}
}
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "login?faces-redirect=true";
}
// ...
}
The logout (and session invalidate) listener: com.example.LogoutListener
#WebListener
public class LogoutListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent event) {
// NOOP.
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
UserManager userManager = (UserManager) event.getSession().getAttribute("user");
if (userManager != null && userManager.getCurrent() != null) {
userManager.getLogins().remove(userManager.getCurrent());
}
}
}
(Do not do this in logout() method! It's the session invalidation which triggers this, the session invalidation will take place when logout() is called OR when session has expired)
In any logged-in view you can obtain the current user and the login count as follows:
<p>Welcome, #{user.current.name}!</p>
<p>Total logged in users: #{user.logins.size()}</p>
get the number of connected users
I'll assume that you mean to get the number of logged-in users.
Basically, you need to have an applicationwide Set<User> with all logged-in users and add the User to it when it logs in and remove the User when it logs out or when its session is destroyed. Here's an example which uses an application scoped managed bean
#ManagedBean(eager=true)
#ApplicationScoped
public class LoginManager implements Serializable {
private Set<User> users = new HashSet<User>();
public Set<User> getUsers() {
return users;
}
}
If you were using Java EE 6 it would have been easy to replace j_security_check by a managed bean method which utilizes the new Servlet 3.0 HttpServletRequest#login() and simultaneously adds the User to the Set<User> of the injected LoginManager bean.
But on Java EE 5 there is no trivial way to hook on it. You would need to check every request for the logged-in user. Best to achieve this is to put the User object in the session whenever there's an UserPrincipal. You can do this using a filter which does roughly the following job in doFilter() method.
UserPrincipal principal = request.getUserPrincipal();
User user = (User) session.getAttribute("user");
if (principal != null && user == null) {
user = userService.findByName(principal.getName());
session.setAttribute("user", user);
LoginManager loginManager = (LoginManager) servletContext.getAttribute("loginManager");
loginManager.getUsers().add(user);
}
Finally, to remove the user from the logins, best is to hook on HttpSessionListener#sessionDestroyed(), assuming that you're invalidating the session on logout. This will also be called when the session expires.
public void sessionDestroyed(HttpSessionEvent event) {
User user = (User) event.getSession().getAttribute("user");
if (user != null) {
LoginManager loginManager = (LoginManager) event.getSession().getServletContext().getAttribute("loginManager");
loginManager.getUsers().remove(user);
}
}

Resources