【问题标题】:How to get number of connected users and their role using j_security_check?如何使用 j_security_check 获取连接用户的数量及其角色?
【发布时间】:2011-09-02 17:31:57
【问题描述】:

我通过托管 bean 以这种方式获取连接用户的用户名(使用 j_security_check):

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

然后以这种方式在 jsf 页面中显示它:#{userBean.username} 但我想不出办法获得连接用户的数量并获得他们的角色。 换句话说,除了用户名、用户角色和连接用户数之外,我还想显示。 我怎么能做到这一点!? 提前感谢您的帮助!

编辑: 我现在可以使用托管 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;
        }

    }

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


}

【问题讨论】:

    标签: jsf java-ee-5 j-security-check userprincipal


    【解决方案1】:

    获取连接用户数

    我假设您的意思是获取登录用户的数量。

    基本上,您需要拥有一个包含所有登录用户的应用程序范围的Set&lt;User&gt;,并在其登录时将User 添加到其中,并在其注销或会话被销毁时删除User。这是一个使用应用程序范围的托管 bean 的示例

    @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,那么使用新的 Servlet 3.0 HttpServletRequest#login() 并同时将 User 添加到注入的LoginManager bean 的Set&lt;User&gt;。 但是在 Java EE 5 上,没有简单的方法可以使用它。您需要检查登录用户的每个请求。实现这一点的最佳方法是将User 对象放入会话中,只要有UserPrincipal。您可以使用filter 来执行此操作,它在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);
        }
    }
    

    【讨论】:

    • 感谢 BalusC!我明天会尝试这个解决方案并给出我的反馈!我想到了一个类似的方法(使用实现 HttpSessionListener 的类和两个三个方法:void SessionCreated()、void SessionDestroyed 和 int getActiveSessionsNumber() {return sessions.size(); }但你的解决方案似乎更好!让我们试试吧!
    • 是的,如果您提供返回 users.getSize()getCount() 方法,您将能够通过 #{loginManager.count} 或其他方式获取视图中的登录计数。
    • 是的,它有:download.oracle.com/javaee/6/api/javax/servlet/http/…Filter 中,您只需将ServletRequest 转换回HttpServletRequest
    • 好的!是的!我使用了错误的属性!对不起!另一件事,servletContext 是从哪里来的?在过滤器类中声明:ServletContext servletContext = .....something; ??
    • 考虑到我现在使用的是 Servlet 3.0,您能否请@BalusC 添加第二个答案(HttpServletRequest#login() 并同时将用户添加到注入的 LoginManager bean 的 Set 中) .如果不是那么多问!!!
    【解决方案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>
    

    用户管理器 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";
        }
    
        // ...
    }
    

    注销(和会话无效)监听器: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>
    

    【讨论】:

    • 太棒了!我想只有一个小版本:从&lt;h:commandButton value="#{user.login}" /&gt;&lt;h:commandButton action="#{user.login}" /&gt; 并为(密码、用户名、登录名)添加吸气剂。再次感谢@BalusC!你是最棒的!
    • 我修复了按钮(抱歉,Stackoverflow 编辑器中没有类似 IDE 的自动完成功能)。 // ... 评论涵盖了 getter/setter,我认为这很明显:)
    • 如果我别无选择,比如 JavaEE5 (WebSphere 7) 和 JSF 2,我将如何实现相同的目标,即 request.login(...)?
    • Set 登录中的信息会保留多长时间?内容什么时候过期?
    • @SeanCoetzee 让LoginManager 将数据存储在共享数据存储中。
    猜你喜欢
    • 2023-04-04
    • 2016-12-26
    • 2017-09-19
    • 2016-04-28
    • 2014-11-27
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多