如果已使用JAAS已经激活(如果用户忘记注销),则删除上一个会话

时间:2014-12-08 19:25:37

标签: java-ee servlets jaas java-ee-7 jdbcrealm

让以下类成为会话范围的CDI托管bean。

@Named
@SessionScoped
public class SessionUtils implements Serializable
{
    private Map<String, Object>sessionMap;
    private static final long serialVersionUID=1l;

    public SessionUtils() {}

    @PostConstruct
    private void init() {
        sessionMap=new HashMap<String, Object>();
    }

    public Map<String, Object> getSessionMap() {
        return sessionMap;
    }
}

地图用于存储用户特定信息。


我正在使用JAAS进行身份验证。登录Filter。它的骨架如下所示。

@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/WEB-INF/jaas/*"}, dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})
public final class SecurityCheck implements Filter
{
    @Inject
    private UserBeanLocal userService;
    @Inject
    private SessionUtils sessionUtils;

    public SecurityCheck() {}

    private void doBeforeProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        String userName = request.getParameter("userName");
        request.login(userName != null ? userName.trim() : "", request.getParameter("password"));
    }

    private void doAfterProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        Map<String, Object> sessionMap = sessionUtils.getSessionMap();

        if (request.isUserInRole("ROLE_ADMIN")) {
            UserTable userTable = userService.setLastLogin(request.getParameter("userName"));
            userTable.setPassword(null);

            //sessionMap.put("user", userTable);
            request.getSession().setAttribute("newUser", new User());

            response.sendRedirect(request.getContextPath() + "/admin_side/Home.xhtml");
        }
        //else {Repeat for other authorities}
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String userName = httpServletRequest.getParameter("userName");
        HttpServletResponse httpServletResponse = ((HttpServletResponse) response);

        try {
            doBeforeProcessing(httpServletRequest, httpServletResponse);
        } catch (ServletException e) {
            httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/utility/LoginError.xhtml");
            return;
        }

        chain.doFilter(request, response);

        doAfterProcessing(httpServletRequest, httpServletResponse);
    }
}

我需要调用以下HttpSessionBindingListener

public final class User implements HttpSessionBindingListener {
    private static final Map<UserTable, HttpSession> logins = new HashMap<UserTable, HttpSession>();

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("valueBound() called.");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("valueUnbound() called.");           
    }
}

只有在沿着以下行使用代码时才会调用重写的方法。

request.getSession().setAttribute("newUser", new User()); //Or remove

但如果将User的实例简单地存储到会话映射中(在该CDI bean中),则不会调用它们。

sessionMap.put("newUser", new User());

在JAAS / CDI中还有其他方法来处理相同的问题 - 模拟HttpSessionBindingListener吗?

我想要做的是:如果用户忘记退出,则应在下次尝试登录时删除(之前仍处于活动状态)会话。


另外一件事:UserTable(不是User - 它只是一个例子。)是一个实际的JPA实体类。需要在该JPA实体上实现HttpSessionBindingListener,这反过来又要求javax.servlet包中对服务层的额外依赖,从而不必要地增加模块之间的耦合。

这可以被隔离,以便HttpSessionBindingListener可以在Web层上实现(无论JPA实体类是什么 - UserTable并仍然为该类服务,即{{1}的实例当UserTable的{​​{1}}实例从valueBound()移除,被另一个会话属性替换为valueUnbound()时,会调用UserTable方法... HttpSession会话本身被破坏/无效)?我希望在高级Java EE中有一些方法。

问题标题不应该如此有意义。我会在以后编辑它,当我设想一个更有意义的标题,或者你可以在那之前自愿编辑它,如果你愿意的话。

2 个答案:

答案 0 :(得分:0)

据我了解,问题是关注,为什么HttpSessionBindingListener仅在您致电request.getSession()时被调用?

只有在调用request.getSession()时才会创建会话,因此会调用侦听器。 因此,您需要调用该方法才能启动会话,或者如果您在请求期间稍后调用该会话,则会启动该方法。

顺便说一句,将HttpSession存储在静态变量中是不好的做法,如果你愿意忘记&#34;它可能会导致内存泄漏。删除它。

为了实现您尝试做的事情,我只在会话监听器中存储一组静态request.getSession().getId()。在过滤器中,我会检查该集合是否具有id,因此您将获得现有会话或创建新会话。 或者仍然存储在地图中,如果您确实需要知道会话属于哪个用户。

答案 1 :(得分:0)

  

如果用户忘记退出,则(先前仍处于活动状态)会话   应该在他/她下次尝试登录时删除。

我通常做的就是简单地丢弃&#34;当前&#34;渲染登录页面时的会话:

request.getSession().invalidate();

换句话说,进入登录页面意味着退出当前会话。

相关问题