让以下类成为会话范围的 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实体类。HttpSessionBindingListener
需要在该 JPA 实体上实现,这反过来又需要对 javax.servlet
包的服务层的额外依赖,从而不必要地增加模块之间的耦合。
是否可以将其隔离,以便可以在 Web 层上实现HttpSessionBindingListener
(无论该 JPA 实体类如何 - UserTable
并且仍然为该类提供服务,即当UserTable
实例放入会话时,调用valueBound()
方法...和valueUnbound()
,当UserTable
的实例从HttpSession
中删除时,替换为另一个会话属性或会话本身被销毁/失效(?我希望在高级Java EE中有一些方法。
问题标题没有应有的意义。稍后,当我设想一个更有意义的标题时,我会编辑它,或者如果你愿意,你可以在那之前自愿编辑它。
我了解,问题如下,为什么只有当你打电话给request.getSession()
时才调用HttpSessionBindingListener
?
仅当您调用request.getSession()
会话时,才会创建会话,因此将调用侦听器。因此,您需要调用该方法才能启动会话,或者如果您稍后在请求期间调用它,它将启动。
顺便说一句,将HttpSession
存储在静态变量中是一种不好的做法,如果您"忘记"删除它,可能会导致内存泄漏。
为了实现您要执行的操作,我将只在会话侦听器中存储一组静态request.getSession().getId()
。在过滤器中,我会检查集合是否具有这样的id
,因此您将获得现有会话或创建一个新会话。或者仍然存储在map中,如果你真的需要知道会话属于哪个用户。
如果用户忘记注销,(上一个仍处于活动状态(会话 应在他/她下次尝试登录时删除。
我通常做的是在呈现登录页面时简单地丢弃"当前"会话:
request.getSession().invalidate();
换句话说,转到登录页面意味着注销当前会话。