使用 Spring 密码更改安全插件使 Grails 中用户的所有其他 http 会话无效的正确方法?

Correct way to invalidate all other http sessions for a user in Grails with Spring Security plugin on password change?

最佳做法是在用户更改密码时使任何其他已登录的 http 会话无效。但是,在带有 Spring 安全插件的 Grails 中,默认情况下不会发生这种情况。使特定用户名的当前会话以外的所有会话无效的正确代码是什么?在 Grails 2.3.x 和 Spring Security 2.0 上观察到此行为。如果更高版本中的行为或代码会有所不同,请将其包含在答案中。

我认为它不会在任何版本的 Grails 上自动发生。实现它的方法是使用 Spring SessionRegistry:

  1. 在resources.groovy
  2. 中配置SessionRegistry
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy
import org.springframework.security.core.session.SessionRegistryImpl
import org.springframework.security.web.session.ConcurrentSessionFilter

beans = {

    sessionRegistry(SessionRegistryImpl)
    concurrencyFilter(ConcurrentSessionFilter){
        sessionRegistry = sessionRegistry
        expiredUrl = '/login'
    }
    sessionAuthenticationStrategy(ConcurrentSessionControlStrategy, sessionRegistry) {
        maximumSessions = -1
    }
}
  1. 在 BootStrap.groovy
  2. 中注册 concurrencyFilter 过滤器
import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.SecurityFilterPosition

class BootStrap {

    def init = { servletContext ->

      SpringSecurityUtils.clientRegisterFilter('concurrencyFilter', SecurityFilterPosition.CONCURRENT_SESSION_FILTER)

      // ...
    }
}
  1. HttpSessionEventPublisher添加到web.xml
    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>
  1. sessionRegistry 注入用户实体并在密码更改时使用它使会话无效(在较新版本的 Grails 中,它宁愿在 GORM 事件侦听器中完成):
    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
            invalidateSessions()
        }
    }

    def invalidateSessions() {
        def principal =  sessionRegistry.getAllPrincipals().find { it.username == username }
        if(principal) {
            sessionRegistry.getAllSessions(principal, true).each { it.expireNow() }
        }
    }

此解决方案适用于 Grails 2.3.11 和 Spring Security 2.0.0。在较新的版本中,情况大不相同。