如何正确注销其他用户

时间:2015-09-30 12:14:37

标签: jsf java-ee jsf-2.2 logout httpsession

在我的网络应用程序中,我正在尝试实现功能,即管理员 能够注销其他当前登录的用户。

到目前为止我做了什么:

  • 我创建了一个POJO来存储重要的用户信息,包括引用用户的HTTP会话。
  • 此POJO正在实施HttpSessionBindingListener
  • 在登录过程中,我将此POJO的一个实例放入SessionMap。通过valueBound方法,我将其放入静态地图中,该地图存储所有此类登录用户信息(在未绑定的事件上,我将其再次删除
  • 在单独的管理部分,我现在可以访问特定用户的HttpSession并使其无效
  • 已登出的用户通过websocket通知他已登出

使HttpSession无效,并调用提到的unbound方法。但问题是,如果以这种方式注销用户仍然能够执行AJAX请求。创建了一个新的hte ViewScoped Bean实例并将其分配给客户端,并且请求针对此新实例。

我期望(或者我想要达到的目标)就是抛出ViewExpiredException,而不是将用户重定向到登录页面。
或者我错过了我的概念中的重要部分?

web.xml中设置适当的安全约束还是仅仅隐藏概念性问题是否足够?

(如果重要的话,Bean不是JSF Bean而是CDI ViewScoped bean。)

应用程序在Glassfish 4.1上运行,Mojarra 2.2.12

SessionBindingListener:

@RequiredArgsConstructor
@EqualsAndHashCode(of = {"user"})
public class UserSessionInfo implements HttpSessionBindingListener {

    @Getter private static final Map<UserSessionInfo, UserSessionInfo> sessions 
         = new HashMap<>(10);

    @Getter private final String user;
    @Getter private HttpSession session;

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        UserSessionInfo usi = sessions.remove(this);
        if (usi != null) {
            HttpSession hs = usi.session;
            if (hs != null) {
                hs.invalidate();
            }
        }
        this.session = event.getSession();
        sessions.put(this, this);
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        sessions.remove(this);
    }

}

登录-方法

public String login() {
        FacesContext context = FacesContext.getCurrentInstance();        
        HttpServletRequest request = 
           (HttpServletRequest) context.getExternalContext().getRequest();
        try {
            request.login(username, password);
            context
                .getExternalContext()
                .getSessionMap().put(username, new UserSessionInfo(/* ...*/)));
            // ..
        } 
        // ....
        return "/index?faces-redirect=true";
    }

管理员 - 注销其他用户的方法:

public void logoff(UserSessionInfo usr) {
    EventBus eventBus = EventBusFactory.getDefault().eventBus();        
    eventBus.publish(CHANNEL, new DialogMessage(/*...*/));        
    usr.getSession().invalidate();           
}

1 个答案:

答案 0 :(得分:0)

如果您的用户的会话确实无效,则所有请求都将失败,ajax或不是。

在我的一个应用中,我有:

  • 安全限制,通过web.xml中的角色
  • 使用HttpSessionListener和Filter进行会话跟踪(过滤器是我在登录时检测tomcat创建的新会话的方式,以避免会话固定)
  • 使用session.invalidate
  • “杀死”另一个会话的可能性

如果会话“在你的背后”重新创建,那一定是因为你有一个不受限制的区域可以访问。要求所有人都使用auth,例如:

<security-constraint>
    <display-name>Authenticated users</display-name>
    <web-resource-collection>
        <web-resource-name>Authenticated users</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

在web.xml中,它应该没问题。