Как получить количество подключенных пользователей и их роль с помощью j_security_check?

Я получаю имя пользователя подключенного пользователя (используя j_security_check) таким образом, через управляемый компонент:

......
    username =   FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal().getName();

А затем отобразите это на странице jsf следующим образом: #{userBean.username} Но я не понял, как получить количество подключенных пользователей и получить их роль. Другими словами, я хочу отображать помимо имени пользователя роль пользователя и количество подключенных пользователей. Как мне этого добиться!? Заранее спасибо за вашу помощь!

РЕДАКТИРОВАТЬ: теперь я могу получить роль подключенного пользователя, используя namedquery в управляемом компоненте:

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;
        }

    }

и на странице xhtml:

<h:outputLabel for="rolefacet" value="Role: "/>
  <h:outputFormat id="rolefacet" value="#{UserBean.userRole.ugroup}" /> 

в то время как ugroup — это имя роли в классе сущностей Users.


РЕДАКТИРОВАТЬ: Одно решение, которое до сих пор не работает для меня, - добавить HttpSessionListener в мой 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();
    }


}

person Hanynowsky    schedule 26.05.2011    source источник


Ответы (2)


Вот базовый начальный пример того, как вы могли бы сделать это, когда вы используете Servlet 3.0 и, таким образом, можете использовать программный вход в систему с помощью нового HttpServletRequest#login() API.

Форма входа: 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>

Компонент управления пользователями: 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";
    }

    // ...
}

Слушатель выхода из системы (и аннулирования сеанса): 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());
        }
    }

}

(Не делайте этого в методе logout()! Это вызывает аннулирование сеанса, аннулирование сеанса произойдет при вызове logout() ИЛИ по истечении срока действия сеанса)

В любом представлении, вошедшем в систему, вы можете получить текущего пользователя и количество входов в систему следующим образом:

<p>Welcome, #{user.current.name}!</p>
<p>Total logged in users: #{user.logins.size()}</p>
person BalusC    schedule 06.07.2011
comment
Замечательный! Я предполагаю, что осталась только одна небольшая редакция: с <h:commandButton value="#{user.login}" /> до <h:commandButton action="#{user.login}" /> и добавление геттеров для (пароль, имя пользователя, логины). Еще раз большое спасибо @BalusC! Ты лучший! - person Hanynowsky; 07.07.2011
comment
Я исправил кнопку (извините, в редакторе Stackoverflow нет автодополнения, подобного IDE). Геттеры/сеттеры описаны в комментарии // ..., я полагаю, это достаточно очевидно :) - person BalusC; 07.07.2011
comment
что, если у меня нет выбора, например, JavaEE5 (WebSphere 7) и JSF 2. Как мне добиться того же, то есть request.login(...)? - person setzamora; 13.04.2012
comment
Как долго хранится информация в логинах Set‹User›? Когда истекает срок действия контента? - person Stephan; 01.08.2017
comment
@Стефан просто Ctrl + F удалить. - person BalusC; 01.08.2017
comment
@BalusC да, я заметил выход из системы, а также удаление (). Позвольте мне перефразировать мой вопрос, пожалуйста. Как я могу гарантировать, что сеанс, поддерживающий список вошедших в систему пользователей (в данном случае Set‹User› логины;), будет поддерживаться вечно (до закрытия приложения). Не закончится ли время сеанса в какой-то момент и информация не потеряется? - person Stephan; 01.08.2017
comment
@Stephan Где вы прочитали, что LoginManager должен быть в рамках сеанса? - person BalusC; 01.08.2017
comment
Любые предложения о том, как заставить это работать в кластерной среде? - person Sean; 26.02.2018
comment
@SeanCoetzee Просто позвольте LoginManager хранить данные в общем хранилище данных. - person BalusC; 26.02.2018

получить количество подключенных пользователей

Я предполагаю, что вы хотите получить количество зарегистрированных пользователей.

По сути, вам нужно иметь приложение Set<User> со всеми зарегистрированными пользователями и добавлять к нему User при входе в систему и удалять User при выходе из системы или при уничтожении его сеанса. Вот пример, в котором используется управляемый компонент с областью действия приложения.

@ManagedBean(eager=true)
@ApplicationScoped
public class LoginManager implements Serializable {

    private Set<User> users = new HashSet<User>();

    public Set<User> getUsers() {
        return users;
    }

}

Если бы вы использовали Java EE 6, было бы легко заменить j_security_check методом управляемого компонента, который использует новый Servlet 3.0 HttpServletRequest#login() и одновременно добавляет User к Set<User> введенного LoginManager компонента. Но в Java EE 5 нет тривиального способа зацепиться за него. Вам нужно будет проверить каждый запрос для вошедшего в систему пользователя. Лучше всего для этого помещать объект User в сеанс всякий раз, когда есть объект UserPrincipal. Вы можете сделать это с помощью фильтра, который выполняет примерно следующую работу в методе doFilter().

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);
}

Наконец, чтобы удалить пользователя из логинов, лучше всего подключиться к HttpSessionListener#sessionDestroyed(), предполагая, что вы аннулируете сеанс при выходе из системы. Это также будет вызвано, когда сеанс истечет.

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);
    }
}
person BalusC    schedule 26.05.2011
comment
Спасибо BalusC! Я попробую это решение завтра и дам свой отзыв! Я имел в виду аналогичный подход (с использованием класса, реализующего HttpSessionListener и двух трех методов: void SessionCreated(), void SessionDestroyed и int getActiveSessionsNumber() {return session.size(); }, но ваше решение кажется лучше! Давайте попробуем! - person Hanynowsky; 27.05.2011
comment
Да, вы сможете получить количество входов в представление с помощью #{loginManager.count} или чего-то еще, если вы предоставите метод getCount(), который возвращает users.getSize(). - person BalusC; 27.05.2011
comment
Да, есть: http://download.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal%28%29 Внутри Filter вам нужно только преобразовать ServletRequest обратно в HttpServletRequest. - person BalusC; 27.05.2011
comment
Ok! Да, это так! Я использовал неправильный атрибут! Извиняюсь! Еще одна вещь, откуда взялся servletContext? Объявлено в классе Filter: ServletContext servletContext = .....something; ?? - person Hanynowsky; 31.05.2011
comment
не могли бы вы @BalusC добавить второй ответ (HttpServletRequest#login() и одновременно добавить пользователя в Set‹User› введенного bean-компонента LoginManager), принимая во внимание, что сейчас я использую Servlet 3.0. Если бы не так много просили!!! - person Hanynowsky; 06.07.2011