21. Session Management
与HTTP会话相关的功能由SessionManagementFilter(会话管理过滤器) 和SessionAuthenticationStrategy(会话身份验证策略)接口的组合来处理,过滤器将这些接口委托给它们。典型的用法包括会话固定保护、防止攻击、检测会话超时以及限制经过身份验证的用户可以同时打开多少个会话
21.1 SessionManagementFilter(回话管理过滤器)
SessionManagementFilter对照SecurityContextRepository的当前内容检查SecurityContextHolder的内容,以确定用户在当前请求期间是否已通过身份验证,通常是通过非交互式身份验证机制,如预身份验证或“记住我”。如果存储库包含一个安全上下文,过滤器什么也不做。如果没有,并且线程本地安全上下文包含一个(非匿名的)身份验证对象,则过滤器假定它们已经由堆栈中的前一个过滤器进行了身份验证。然后,它将调用已配置的会话身份验证策略。
如果用户当前未通过身份验证,过滤器将检查是否请求了无效的会话标识(例如,由于超时),并将调用已配置的InvalidSessionStrategy(如果设置了)。最常见的行为就是重定向到一个固定的网址,这被封装在标准实现simpleredirectinvalisessionstrategy中。如前所述,当通过命名空间配置无效的会话URL时,也使用后者。
21.2 SessionAuthenticationStrategy(会话身份验证策略)
会话身份验证策略(SessionAuthenticationStrategy )由会话管理筛选器(SessionManagementFilter )和抽象身份验证处理筛选器(AbstractAuthenticationProcessingFilter)使用,因此,例如,如果您正在使用一个定制的表单登录类,那么您需要将它注入到这两个类中。在这种情况下,将命名空间和自定义beans相结合的典型配置可能如下所示:
![](https://upload-images.jianshu.io/upload_images/23862095-3aaa948f64b275d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
请注意,如果在实现HttpSessionBindingListener(包括Spring会话范围内的bean)的会话中存储bean,则使用默认的会话固定保护策略可能会导致问题。有关更多信息,请参见该类的Javadoc。
21.3 Concurrency Control(并发控制)
Spring Security能够防止一个主体同时向同一个应用程序进行身份验证超过指定的次数。许多独立软件开发商利用这一点来实施许可,而网络管理员喜欢这一功能,因为它有助于防止人们共享登录名。例如,您可以阻止用户“蝙蝠侠”从两个不同的会话登录到网络应用程序。您可以让他们以前的登录过期,也可以在他们再次尝试登录时报告错误,防止他们再次登录。请注意,如果您使用第二种方法,尚未明确注销的用户(例如,刚刚关闭浏览器的用户)将无法再次登录,直到其原始会话到期。
命名空间支持并发控制,因此请查看前面的命名空间章节,了解最简单的配置。有时候你需要定制一些东西。
该实现使用会话身份验证策略(SessionAuthenticationStrategy)的专用版本,称为并发会话身份验证策略(ConcurrentSessionControlAuthenticationStrategy)。
以前,并发身份验证检查是由提供者管理器(ProviderManager)进行的,它可以通过并发会话控制器(ConcurrentSessionController)注入。后者将检查用户是否试图超过允许的会话数量。但是,这种方法要求预先创建一个超文本传输协议会话,这是不可取的。在Spring Security 3中,用户首先由身份验证管理器进行身份验证,一旦他们成功通过身份验证,就会创建一个会话,并检查是否允许他们打开另一个会话。
要使用并发会话支持,您需要将以下内容添加到web.xml中:
![](https://upload-images.jianshu.io/upload_images/23862095-09de42614b5e10e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
此外,您需要将并发会话过滤器添加到您的过滤器链代理中。ConcurrentSessionFilter需要两个属性:sessionRegistry(通常指向SessionRegistryImpl的一个实例)和ExpiredR1(当会话过期时指向要显示的页面)。使用命名空间创建过滤器链代理和其他默认beans的配置可能如下所示:
![](https://upload-images.jianshu.io/upload_images/23862095-2668571bbee104fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
每次HttpSession开始或终止时,将侦听器添加到web.xml会导致应用程序事件发布到Spring应用程序上下文。这一点非常重要,因为它允许在会话结束时通知SessionRegistryImpl。没有它,用户将永远无法再次登录,一旦他们超过了他们的会话允许,即使他们退出另一个会话或它超时。
21.3.1 Querying the SessionRegistry for currently authenticated users and their sessions
在会话注册表中查询当前经过身份验证的用户及其会话。
通过命名空间或使用普通beans来设置并发控制有一个有用的副作用,它为您提供了一个对SessionRegistry的引用,您可以在应用程序中直接使用它,因此,即使您不想限制用户可能拥有的会话数量,也值得设置基础结构。您可以将maximumSession属性设置为-1,以允许无限制的会话。如果您正在使用命名空间,您可以使用session-registry-alias属性为内部创建的会话注册表(SessionRegistry )设置一个别名,提供一个可以插入到您自己的beans中的引用。
getAllPrincipals()方法为您提供了当前经过身份验证的用户的列表。您可以通过调用getAllSessions(对象主体,布尔值includeExpiredSessions)方法来列出用户的会话,该方法返回会话信息对象的列表。您也可以通过在会话信息实例上调用expireNow()来使用户的会话过期。当用户返回应用程序时,他们将被阻止继续。例如,您可能会发现这些方法在管理应用程序中很有用。查看Javadoc了解更多信息。
会话管理过滤器不会检测到在身份验证后执行重定向的机制进行的身份验证(如表单登录),因为在身份验证请求期间不会调用过滤器。在这些情况下,会话管理功能必须单独处理。