【问题标题】:How to handle session timeout when using Servlet 3.0 programmatic security使用 Servlet 3.0 编程安全性时如何处理会话超时
【发布时间】:2012-03-14 14:50:25
【问题描述】:

关于 Servlet 3.0 编程安全性,当会话超时时,无法调用 HttpServletRequest#logout()

用户是否保持登录到 JAAS?

如果是这样,在会话超时后处理退出 JAAS 的最佳做法是什么?

容器如何处理用户后续的再次登录请求并在会话超时后创建新会话?

顺便说一句,在使用 Servlet 3.0 编程安全性时,使用以下三种方法来处理会话超时的优缺点是什么:

  1. HttpSessionListener#sessionDestroyed()
  2. 使@ManagedBean @SessionScoped LoginManager 实现HttpSessionBindingListener 并在valueUnbound 中执行一些操作。
  3. 在 LoginManager 中使用 @PreDestroy 注释方法。

任何其他建议的方法/最佳实践建议肯定会受到赞赏。

【问题讨论】:

  • “核心 Java 服务器端面”p。 525 表示“目前,在使用容器管理的安全性时,没有关于注销或切换身份的规范。”
  • 我还遇到过一些关于 J2EE 安全性的博客抱怨,抱怨无效会话不能很好地替代正式注销,但是这些博客比较老,是在 Servlet 3.0 之前编写的,它提供了一个表示以编程方式注销。
  • 显然您的 CJSF 版本早于 Servlet 3.0。

标签: java jakarta-ee jaas servlet-3.0


【解决方案1】:

在 Servlet 规范中的某处有一个声明,大意是会话无效正好对应于其中没有 Principal 的状态。这是关键。 logout() 和 timeout 都使会话无效,并且使会话无效会从中删除 Principal 及其所有值绑定。

JAAS 真正所做的只是允许LoginModules 为用户及其角色在Subject 中累积委托人。 JAAS logout() 方法真正需要做的就是清除由同一模块的 login() 或者更可能是 commit() 方法添加的主体的主题,如果您有,这实际上只是为了总体安全向主题添加了诸如私有凭据之类的内容。由于 logout() 不会由与 login()/commit() 相同的实例执行,因此删除必须基于主体类而不是主体的内部集合。

会话到期时不会调用 JAAS logout(),但由于 Principal 已从会话中删除,这对任何人来说都无关紧要。

如果您想跟踪会话终止出于其他原因,例如记录,使您的用户 bean 成为会话绑定侦听器,并在 valueUnbound() 方法中将终止记录为注销:根据我的经验,这是 100% 可靠的。

为了回答您的其他问题,不存在“登录到 JAAS”这样的状态:JAAS为容器提供登录/注销服务,而不是为它自己提供;并且新登录是新登录,进入新会话,无论前一个会话是否过期。

【讨论】:

  • +1 简洁(正确)答案=)从这篇文章中删除了许多令人反感的 cmets,使得一些(删除的)答案语气不连贯。一切都好,结局好。
  • 感谢@EJP。有趣的是,如果我在调用 request.logout() 后设置断点,我可以看到会话 not 无效,尽管 Principal is 从会话中删除。重新登录后 JSESSIONID 不会更改,并且会话对象保持完全相同的实例(例如@15961),这有点令人不安。当然,除了 request.logout() 之外或代替 request.logout() 使用 session.invalidate() 会导致 JSESSIONID 和会话对象被更改。这是在 JBoss AS7 上。最重要的是,无论调用这两种方法中的哪一种,都会删除 Principal 。
  • @PatrickGarner HttpServletRequest.html.logout() 的所有文档都说它确实如此。 Session.invalidate() 会进行无效化,但它不会影响当前请求或其主体,因此如果您只使用它,您仍然可以像用户登录一样显示内容。您必须同时调用它们。真是奇怪的生意。
【解决方案2】:

会话管理与 JAAS 没有直接关联。会话管理实际上取决于您的容器。

在 Jetty 8 中,会话管理由 SessionManager(在上下文级别)和 SessionIdManager(在服务器级别)处理。

浏览器将会话 ID 发送到服务器。实现 SessionManager 的类验证会话 ID。如果会话过期,则会话失效并被移除,并通知会话监听器。

我不知道你为什么需要“注销”用户,但你应该能够将你的注销挂在侦听器上。

“保持登录 JAAS”对您的容器可能意义不大。 Jetty 没有用户/主体/主题缓存,因此除非您像我们一样自己实现缓存,否则您不会“保持登录状态”。

JAAS 模块只提供身份验证和授权;没有别的。

添加

当会话过期时,服务器会返回 302 并重定向到登录页面。页面上提交的表单调用登录模块(可能是 JAAS 模块),并在成功验证后创建一个新会话和会话 ID,通常通过 cookie(或 URL 重写)的方式将其发送回浏览器。

除非您的应用为所有上下文处理单个上下文 ID,否则我认为您不应在会话到期时执行任何类型的编程注销;您可以“无效”在另一个上下文中仍然具有有效会话的用户。

【讨论】:

  • 我不知道 JAAS 的内部是什么。我不知道 Web 容器如何与 JAAS 交互,例如存储主题、主体和组的位置,调用 HttpServletRequest#logout() 与会话超时时实际发生的情况。如果会话超时,调用 HttpServletRequest#logout() 时执行的内务管理是否也由容器执行?如果没有,为什么在这种情况下不需要?
  • 在阅读了 Servlet 3.0 规范之后。和 JAAS 规范。和 JEE 6 规范。我不知道上述问题的答案,我希望有人可以指出我的文档或开发列表线程,甚至可能是 JBoss/Tomcat/Jetty/Glassfish 设计文档或源代码 sn-ps 显示发生了什么会话超时时发送到 Subject、Principal 和 Group 实例。很高兴知道在调用 HttpServletRequest#logout() 时这些对象会发生什么。在这两种情况下如何处理注销之间的差异(如果有的话)会很大。
猜你喜欢
  • 2014-09-04
  • 2016-08-11
  • 2018-01-24
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 2015-08-05
  • 2014-07-17
  • 2012-12-24
相关资源
最近更新 更多