grails 3并发会话 [英] grails 3 with concurrent session

查看:159
本文介绍了grails 3并发会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

iam试图从2.1.1升级我的项目。到3.1.1



我有一些与并发会话
有关的问题。例如..



i我在浏览器chrome
上使用用户名AAA登录,然后其他用户在其他浏览器上再次使用用户名AAA登录,然后用户名AAA将自动在浏览器chrome注销

..继承人我的代码

登录控制器

  package accounter 

import com.vastpalaso.security.User
import grails.converters.JSON
import grails.plugin.springsecurity.SpringSecurityUtils
import org .slf4j.Logger
导入org.slf4j.LoggerFactory
导入grails.converters.JSON
导入org.springframework.security.access.annotation.Secured
导入org.springframework.security .authentication.AccountExpiredException
导入org.springframework.security.authentication.AuthenticationTrustResolver
导入org.springframework.security.authentication.CredentialsExpiredException
导入org.springframew ork.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.Authentication
import org.springframework.security.core.context。 SecurityContextHolder
导入org.springframework.security.web.WebAttributes
导入grails.plugin.springsecurity.SpringSecurityUtils
导入org.springframework.security.web.authentication.session.SessionAuthenticationException

import javax.servlet.http.HttpServletResponse
$ b @Secured('permitAll')
LoginController {

/ ** AuthenticationTrustResolver的依赖注入。 * /
AuthenticationTrustResolver authenticationTrustResolver

/ ** springSecurityService的依赖注入。 * /
def springSecurityService
def cifService

private static final Logger logger = LoggerFactory.getLogger(this)

/ **默认操作;如果已登录,则重定向到defaultTargetUrl,否则重定向到/ login / auth。 * /
def index(){
if(springSecurityService.isLoggedIn()){
redirect uri:conf.successHandler.defaultTargetUrl
}
else {
重定向动作:'auth',params:params
}
}

/ **显示登录页面。 * /
def auth(){

def conf = getConf()

if(springSecurityService.isLoggedIn()){
redirect uri:conf .successHandler.defaultTargetUrl
返回
}

字符串postUrl = request.contextPath + conf.apf.filterProcessesUrl
渲染视图:'auth',model:[postUrl: postUrl,
rememberMeParameter:conf.rememberMe.parameter,
usernameParameter:conf.apf.usernameParameter,
passwordParameter:conf.apf.passwordParameter,
gspLayout:conf.gsp.layoutAuth]
}

/ ** Ajax请求的重定向操作。 * /
def authAjax(){
response.setHeader'Location',conf.auth.ajaxLoginFormUrl
render(status:HttpServletResponse.SC_UNAUTHORIZED,text:'Unauthorized')
}

/ **显示拒绝页面。 * /
def denied(){
if(springSecurityService.isLoggedIn()&&; amp;& authenticationTrustResolver.isRememberMe(authentication)){
//有cookie,但页面被IS_AUTHENTICATED_FULLY或等效表达式)
重定向动作:'full',params:params
return
}

[gspLayout:conf.gsp.layoutDenied]
}

/ **具有remember-me Cookie但访问IS_AUTHENTICATED_FULLY页面的用户的登录页面。 * /
def full(){
def conf = getConf()
渲染视图:'auth',params:params,
模型:[hasCookie:authenticationTrustResolver.isRememberMe(authentication ),
postUrl:request.contextPath + conf.apf.filterProcessesUrl,
rememberMeParameter:conf.rememberMe.parameter,
usernameParameter:conf.apf.usernameParameter,
passwordParameter:conf。 apf.passwordParameter,
gspLayout:conf.gsp.layoutAuth]
}

/ **登录失败后回调。使用警告消息重定向到授权页面。 * /
def authfail(){
def username = session ['SPRING_SECURITY_LAST_USERNAME']
String msg =''
def exception = session [WebAttributes.AUTHENTICATION_EXCEPTION]
if(exception){
if(exception instanceof AccountExpiredException){
msg = message(code:'springSecurity.errors.login.expired')
}
else if(exception instanceof (代码:'springSecurity.errors.login.passwordExpired')
}
else if(exception instanceof DisabledException){
msg = message(code: 'springSecurity.errors.login.disabled')
}
else if(例外情况为LockedException){
msg = message(code:'springSecurity.errors.login.locked')
}
else if(SessionAut的异常instanceof henticationException){
msg = exception.getMessage()
printlntest
}
else {
msg = message(code:'springSecurity.errors.login。失败')
}
}

尝试{
boolean block = false;
$ b block = cifService.addTryLogin(username)$ b $ if if(session){
render([error:msg,block:block,reload:false] as JSON)
}
else {
render([error:msg,block:block,reload:true] as JSON)
}
}
// catch unknown RuntimeException,重定向到Error 500服务器错误页面
catch(RuntimeException e){
logger.error(e.getMessage(),e)
重定向(controller:error,action:serverError )
return
}

if(springSecurityService.isAjax(request)){
render([error:msg] as JSON)
}
else {
flash.message = msg
重定向动作:'auth',params:params
}
}

/ ** Ajax成功重定向网址。 * /
def ajaxSuccess(){
def user = com.vastpalaso.security.User.findByUsername(springSecurityService.authentication.name)
def userDetails = com.vastpalaso.security.UserDetails.findByUser (user)
def cifUsergetCif

try {
cifUsergetCif = com.vastpalaso.app.cif.CifUser.findByUserDetails(userDetails)
session.setAttribute(company ,cifUsergetCif.cif.corpName)
}
catch(Exception e){
printlne =+ e
println您正在以管理员身份登录!


尝试{

printlnparams =+ params
def ipAddress = request.getHeader(Client-IP)$ b $如果(!ipAddress){
ipAddress = request.getHeader(X-Forwarded-For)
}
if(!ipAddress){
ipAddress = request.getRemoteAddr( )
}

try {

cifService.resetTryLoginAddInfo(userDetails,ipAddress,session.id)
} catch(Exception e){
printlne =+ e
}

session.setAttribute(alias,userDetails.userAlias)
session.setAttribute(fullName,userDetails.firstName + + userDetails.lastName)
session.setAttribute(change,userDetails.forceChangePassword)
session.setAttribute(userType,userDetails.userType)


if(userDetails.language!= null) {
session [org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME] = new Locale(userDetails.language)
}
else {
session [org.springframework。 web.servlet.i18n.SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME] = new Locale(id)
}
buildMenuList()
printlntest =
if(params.callback){
render$ {params.callback}($ {[success:true,id:userDetails.id,change:userDetails.forceChangePassword,username:springSecurityService.authentication.name,fullName:(userDetails.firstName ++ ))
}
else {
render([成功:true,id:userDetails.id,更改:userDetails.forceChangePassword,用户名:springSecurityService.authentication。名称,全名:(userDetails.firstName ++ userDetails.lastName)]作为JSON)
}
}
//捕获未知的RuntimeException,重定向到Error 500服务器错误页面$ b $ catch(RuntimeException e){
logger.error(e.getMessage(),e)
redirect(controller:error,action:serverError)
return
}

render([success:true,username:authentication.name] as JSON )
}


/ ** Ajax拒绝重定向网址。 * /
def ajaxDenied(){
render([error:'access denied'] as JSON)
}

protected getAuthentication(){
SecurityContextHolder.context?.authentication
}

保护ConfigObject getConf(){
SpringSecurityUtils.securityConfig
}

def concurrentSession = {

def msg =您的帐户已从其他浏览器或位置登录。

if(springSecurityService.isAjax(request)){
render([error:msg] as JSON)
}
else {
flash.message = msg
重定向操作:'auth',params:params
}

}
}

这是resouces.groovy

  //将您的Spring DSL代码这里
导入org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
import com.vastpalaso.helper.CustomSessionLogoutHandler
import org.springframework.security.web.session.ConcurrentSessionFilter
beans = {

sessionRegistry(SessionRegistryImpl)

customSessionLogoutHandler(CustomSessionLogoutHandler,ref('sessionRegistry'))

concurrencyFilter(ConcurrentSessionFilter){
sessionRegistry = sessionRegistry
logoutHandlers = [ref(rememberMeServices), ref(securityContextLogoutHandler)]
expiredUrl ='/ login / concurrentSession'
}

concurrentSessionControlAuthenticationStrategy(ConcurrentSessionControlAuthenticationStrategy,ref('sessionRegistry')){
exceptionIfMaximumExceeded = true
maximumSessions = 1
}

sessionFixationProtectionStrategy(SessionFixationProtectionStrategy){
migrateSessionAttributes = true
alwaysCreateSession = true
}
registerSes sionAuthenticationStrategy(RegisterSessionAuthenticationStrategy,ref('sessionRegistry'))
$ b $ sessionAuthenticationStrategy(CompositeSessionAuthenticationStrategy,[ref('concurrentSessionControlAuthenticationStrategy'),ref('sessionFixationProtectionStrategy'),ref('registerSessionAuthenticationStrategy')])


jmsConnectionFactory(org.apache.activemq.ActiveMQConnectionFactory){brokerURL =tcp:// localhost:61616}
}

这是我的代码,我从这里复制 page

  package com.vastpalaso.helper; 

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

导入org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert;
import org.springframework.security.core.session.SessionRegistry;

/ **
* {@link CustomSessionLogoutHandler}负责在注销时删除{@link SessionRegistry}。接下来的请求将由框架生成
* new {@link SessionRegistry}。
*
* @author Mohd Qusyairi
* @since 0.1
* /
public final class CustomSessionLogoutHandler实现LogoutHandler {
private final SessionRegistry sessionRegistry;
$ b $ / **
*创建一个新实例
* @param sessionRegistry {@link SessionRegistry}使用
* /
public CustomSessionLogoutHandler(SessionRegistry sessionRegistry){
Assert.notNull(sessionRegistry,sessionRegistry不能为null);
this.sessionRegistry = sessionRegistry;
}

/ **
*清除{@link SessionRegistry}
*
* @see org.springframework.security.web.authentication。 logout.LogoutHandler#logout(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse,
* org.springframework.security.core.Authentication)
* /
public void logout(HttpServletRequest请求,HttpServletResponse响应,
身份验证身份验证){
this.sessionRegistry.removeSessionInformation(request.getSession()。getId());



$ div $解析方案

将会过期当前登录的用户(相同的用户名和密码)。新用户可以继续登录,而不会有任何问题。



通过将其添加到src文件夹中来创建SessionAuthenticationStrategy的新实现。在grails 3中,(src / main / groovy)在grails(2.x src / groovy)中。
我根据您想实现的目的将其称为自定义名称,并保存为 ConcurrentSingleSessionAuthenticationStrategy.groovy

  package com.myapp.test; 

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

导入org.springframework.security.core.Authentication;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.util.Assert;
import org.springframework.security.core.session.SessionRegistry;
导入grails.plugin.springsecurity.SpringSecurityUtils;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

/ **
*用于在成功完成
* {@link身份验证}后向{@link SessionRegistry}注册用户的策略。
*
*< p>
* {@link RegisterSessionAuthenticationStrategy}通常与
* {@link CompositeSessionAuthenticationStrategy}和
* {@link ConcurrentSessionControlAuthenticationStrategy}结合使用,但如果使用
,则可以自行使用*需要跟踪会话,但不需要控制并发。
*
*< p>
*注意:使用{@link SessionRegistry}时,必须删除所有会话(包括
*超时会话)。这通常通过添加
* {@link HttpSessionEventPublisher}来完成。
*
* @see CompositeSessionAuthenticationStrategy
*
* @author Luke Taylor
* @author Rob Winch
* @since 3.2
* /
public class ConcurrentSingleSessionAuthenticationStrategy实现
SessionAuthenticationStrategy {
private SessionRegistry sessionRegistry;

/ **
* @param sessionRegistry会话注册表,当
*认证会话改变时应该更新会话注册表。
* /
public ConcurrentSingleSessionAuthenticationStrategy(SessionRegistry sessionRegistry){
Assert.notNull(sessionRegistry,SessionRegistry不能为null);
this.sessionRegistry = sessionRegistry;
}
/ **
*除了超类的步骤之外,sessionRegistry将会使用新的会话信息删除
*。
* /
public void onAuthentication(认证认证,
HttpServletRequest请求,HttpServletResponse响应){

def sessions = sessionRegistry.getAllSessions(
authentication.getPrincipal (),false);

def principals = sessionRegistry.getAllPrincipals()
sessions.each {
if(it.principal == authentication.getPrincipal()){
it.expireNow( )
}
}


}
}

resources.groovy 中:

  import org.springframework.security .web.authentication.session.SessionFixationProtectionStrategy; 
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
import org.springframework.security.core.session.SessionRegistryImpl;
import com.myapp.test.ConcurrentSingleSessionAuthenticationStrategy;
import org.springframework.security.web.session.ConcurrentSessionFilter
//将您的Spring DSL代码放在这里
beans = {
sessionRegistry(SessionRegistryImpl)
// I看到你没有这个。非常危险!
sessionFixationProtectionStrategy(SessionFixationProtectionStrategy){
migrateSessionAttributes = true
alwaysCreateSession = true
}
//启动bean
concurrentSingleSessionAuthenticationStrategy(ConcurrentSingleSessionAuthenticationStrategy,ref('sessionRegistry' ))
registerSessionAuthenticationStrategy(RegisterSessionAuthenticationStrategy,ref('sessionRegistry'))
sessionAuthenticationStrategy(CompositeSessionAuthenticationStrategy,[ref('concurrentSingleSessionAuthenticationStrategy'),ref('sessionFixationProtectionStrategy'),ref('registerSessionAuthenticationStrategy')])
concurrentSessionFilter(ConcurrentSessionFilter,ref('sessionRegistry'))
}

最后添加这一行:

  grails.plugin.springsecurity.filterChain.filterNames = [ securityContextPersistenceFilter','logoutFilter','concurrentSessionFilter','rememberMeAuthenticationFilter','anonymousAuthenticationFilter','exceptionTranslationFilter','filterInvocationInterceptor'] 

希望这会有所帮助。

iam trying to upgrade my project from 2.1.1. to 3.1.1

i have some problem with concurrent session for example..

i am login with username "AAA" on browser "chrome" then other user is login again with username "AAA" on other browser then username "AAA" will automatically logout on browser "chrome"

..heres my code

login controller

package accounter

import com.vastpalaso.security.User
import grails.converters.JSON
import grails.plugin.springsecurity.SpringSecurityUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import grails.converters.JSON
import org.springframework.security.access.annotation.Secured
import org.springframework.security.authentication.AccountExpiredException
import org.springframework.security.authentication.AuthenticationTrustResolver
import org.springframework.security.authentication.CredentialsExpiredException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.WebAttributes
import grails.plugin.springsecurity.SpringSecurityUtils
import org.springframework.security.web.authentication.session.SessionAuthenticationException

import javax.servlet.http.HttpServletResponse

@Secured('permitAll')
class LoginController {

    /** Dependency injection for the authenticationTrustResolver. */
    AuthenticationTrustResolver authenticationTrustResolver

    /** Dependency injection for the springSecurityService. */
    def springSecurityService
    def cifService

    private static final Logger logger = LoggerFactory.getLogger(this)

    /** Default action; redirects to 'defaultTargetUrl' if logged in, /login/auth otherwise. */
    def index() {
        if (springSecurityService.isLoggedIn()) {
            redirect uri: conf.successHandler.defaultTargetUrl
        }
        else {
            redirect action: 'auth', params: params
        }
    }

    /** Show the login page. */
    def auth() {

        def conf = getConf()

        if (springSecurityService.isLoggedIn()) {
            redirect uri: conf.successHandler.defaultTargetUrl
            return
        }

        String postUrl = request.contextPath + conf.apf.filterProcessesUrl
        render view: 'auth', model: [postUrl: postUrl,
                                     rememberMeParameter: conf.rememberMe.parameter,
                                     usernameParameter: conf.apf.usernameParameter,
                                     passwordParameter: conf.apf.passwordParameter,
                                     gspLayout: conf.gsp.layoutAuth]
    }

    /** The redirect action for Ajax requests. */
    def authAjax() {
        response.setHeader 'Location', conf.auth.ajaxLoginFormUrl
        render(status: HttpServletResponse.SC_UNAUTHORIZED, text: 'Unauthorized')
    }

    /** Show denied page. */
    def denied() {
        if (springSecurityService.isLoggedIn() && authenticationTrustResolver.isRememberMe(authentication)) {
            // have cookie but the page is guarded with IS_AUTHENTICATED_FULLY (or the equivalent expression)
            redirect action: 'full', params: params
            return
        }

        [gspLayout: conf.gsp.layoutDenied]
    }

    /** Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page. */
    def full() {
        def conf = getConf()
        render view: 'auth', params: params,
                model: [hasCookie: authenticationTrustResolver.isRememberMe(authentication),
                        postUrl: request.contextPath + conf.apf.filterProcessesUrl,
                        rememberMeParameter: conf.rememberMe.parameter,
                        usernameParameter: conf.apf.usernameParameter,
                        passwordParameter: conf.apf.passwordParameter,
                        gspLayout: conf.gsp.layoutAuth]
    }

    /** Callback after a failed login. Redirects to the auth page with a warning message. */
    def authfail() {
        def username = session['SPRING_SECURITY_LAST_USERNAME']
        String msg = ''
        def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
        if (exception) {
            if (exception instanceof AccountExpiredException) {
                msg = message(code: 'springSecurity.errors.login.expired')
            }
            else if (exception instanceof CredentialsExpiredException) {
                msg = message(code: 'springSecurity.errors.login.passwordExpired')
            }
            else if (exception instanceof DisabledException) {
                msg = message(code: 'springSecurity.errors.login.disabled')
            }
            else if (exception instanceof LockedException) {
                msg = message(code: 'springSecurity.errors.login.locked')
            }
            else if (exception instanceof SessionAuthenticationException){
                msg = exception.getMessage()
                println "test"
            }
            else {
                msg = message(code: 'springSecurity.errors.login.fail')
            }
        }

        try {
            boolean block = false;

            block = cifService.addTryLogin(username)
            if(session){
                render([error: msg, block: block, reload: false] as JSON)
            }
            else{
                render([error: msg, block: block, reload: true] as JSON)
            }
        }
        //catch unknown RuntimeException, redirect to Error 500 server Error page
        catch (RuntimeException e) {
            logger.error(e.getMessage(), e)
            redirect(controller: "error", action: "serverError")
            return
        }

        if (springSecurityService.isAjax(request)) {
            render([error: msg] as JSON)
        }
        else {
            flash.message = msg
            redirect action: 'auth', params: params
        }
    }

    /** The Ajax success redirect url. */
    def ajaxSuccess() {
        def user = com.vastpalaso.security.User.findByUsername(springSecurityService.authentication.name)
        def userDetails = com.vastpalaso.security.UserDetails.findByUser(user)
        def cifUsergetCif

        try{
            cifUsergetCif = com.vastpalaso.app.cif.CifUser.findByUserDetails(userDetails)
            session.setAttribute("company",cifUsergetCif.cif.corpName)
        }
        catch (Exception e){
            println "e = "+e
            println "You are loginning as admin!"
        }

        try {

            println "params = "+params
            def ipAddress = request.getHeader("Client-IP")
            if (!ipAddress) {
                ipAddress = request.getHeader("X-Forwarded-For")
            }
            if (!ipAddress) {
                ipAddress = request.getRemoteAddr()
            }

            try{

                cifService.resetTryLoginAddInfo(userDetails, ipAddress, session.id)
            }catch (Exception e){
                println "e = "+e
            }

            session.setAttribute("alias", userDetails.userAlias)
            session.setAttribute("fullName", userDetails.firstName + " " + userDetails.lastName)
            session.setAttribute("change", userDetails.forceChangePassword)
            session.setAttribute("userType", userDetails.userType)


            if(userDetails.language != null){
                session[org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME] = new Locale(userDetails.language)
            }
            else{
                session[org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME] = new Locale("id")
            }
            buildMenuList()
            println "test = "
            if (params.callback) {
                render"${params.callback} (${[success: true,id: userDetails.id ,change: userDetails.forceChangePassword, username: springSecurityService.authentication.name, fullName: (userDetails.firstName + " " + userDetails.lastName)] as JSON})"
            }
            else {
                render([success: true,id: userDetails.id, change: userDetails.forceChangePassword, username: springSecurityService.authentication.name, fullName: (userDetails.firstName + " " + userDetails.lastName)] as JSON)
            }
        }
        //catch unknown RuntimeException, redirect to Error 500 server Error page
        catch (RuntimeException e) {
            logger.error(e.getMessage(), e)
            redirect(controller: "error", action: "serverError")
            return
        }

        render([success: true, username: authentication.name] as JSON)
    }


    /** The Ajax denied redirect url. */
    def ajaxDenied() {
        render([error: 'access denied'] as JSON)
    }

    protected Authentication getAuthentication() {
        SecurityContextHolder.context?.authentication
    }

    protected ConfigObject getConf() {
        SpringSecurityUtils.securityConfig
    }

    def concurrentSession = {

        def msg = "Your account is logged in from another browser or location."

        if (springSecurityService.isAjax(request)) {
            render([error: msg] as JSON)
        }
        else {
            flash.message = msg
            redirect action: 'auth', params: params
        }

    }
}

this is resouces.groovy

// Place your Spring DSL code here
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
import com.vastpalaso.helper.CustomSessionLogoutHandler
import org.springframework.security.web.session.ConcurrentSessionFilter
beans = {

    sessionRegistry(SessionRegistryImpl)

    customSessionLogoutHandler(CustomSessionLogoutHandler,ref('sessionRegistry'))

    concurrencyFilter(ConcurrentSessionFilter) {
        sessionRegistry = sessionRegistry
        logoutHandlers = [ref("rememberMeServices"), ref("securityContextLogoutHandler")]
        expiredUrl='/login/concurrentSession'
    }

    concurrentSessionControlAuthenticationStrategy(ConcurrentSessionControlAuthenticationStrategy,ref('sessionRegistry')){
        exceptionIfMaximumExceeded = true
        maximumSessions = 1
    }

    sessionFixationProtectionStrategy(SessionFixationProtectionStrategy){
        migrateSessionAttributes = true
        alwaysCreateSession = true
    }
    registerSessionAuthenticationStrategy(RegisterSessionAuthenticationStrategy,ref('sessionRegistry'))

    sessionAuthenticationStrategy(CompositeSessionAuthenticationStrategy,[ref('concurrentSessionControlAuthenticationStrategy'),ref('sessionFixationProtectionStrategy'),ref('registerSessionAuthenticationStrategy')])


    jmsConnectionFactory(org.apache.activemq.ActiveMQConnectionFactory) { brokerURL = "tcp://localhost:61616" }
}

and this is my code where i copy from this page

package com.vastpalaso.helper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert;
import org.springframework.security.core.session.SessionRegistry;

/**
 * {@link CustomSessionLogoutHandler} is in charge of removing the {@link SessionRegistry} upon logout. A
 * new {@link SessionRegistry} will then be generated by the framework upon the next request.
 *
 * @author Mohd Qusyairi
 * @since 0.1
 */
public final class CustomSessionLogoutHandler implements LogoutHandler {
    private final SessionRegistry sessionRegistry;

    /**
     * Creates a new instance
     * @param sessionRegistry the {@link SessionRegistry} to use
     */
    public CustomSessionLogoutHandler(SessionRegistry sessionRegistry) {
        Assert.notNull(sessionRegistry, "sessionRegistry cannot be null");
        this.sessionRegistry = sessionRegistry;
    }

    /**
     * Clears the {@link SessionRegistry}
     *
     * @see org.springframework.security.web.authentication.logout.LogoutHandler#logout(javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse,
     * org.springframework.security.core.Authentication)
     */
    public void logout(HttpServletRequest request, HttpServletResponse response,
                       Authentication authentication) {
        this.sessionRegistry.removeSessionInformation(request.getSession().getId());
    }
}

解决方案

this will expire currently logged in user (same username and password). The new user can continue to login without any issue.

Create new implementation of SessionAuthenticationStrategy by adding this to src folder. In grails 3, (src/main/groovy) in grails (2.x src/groovy). I call this a custom name based on what you want to achieve save this as ConcurrentSingleSessionAuthenticationStrategy.groovy:

    package com.myapp.test;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.security.core.Authentication;
    import org.springframework.security.web.session.HttpSessionEventPublisher;
    import org.springframework.util.Assert;
    import org.springframework.security.core.session.SessionRegistry;
    import grails.plugin.springsecurity.SpringSecurityUtils;
    import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

    /**
     * Strategy used to register a user with the {@link SessionRegistry} after successful
     * {@link Authentication}.
     *
     * <p>
     * {@link RegisterSessionAuthenticationStrategy} is typically used in combination with
     * {@link CompositeSessionAuthenticationStrategy} and
     * {@link ConcurrentSessionControlAuthenticationStrategy}, but can be used on its own if
     * tracking of sessions is desired but no need to control concurrency.
     *
     * <p>
     * NOTE: When using a {@link SessionRegistry} it is important that all sessions (including
     * timed out sessions) are removed. This is typically done by adding
     * {@link HttpSessionEventPublisher}.
     *
     * @see CompositeSessionAuthenticationStrategy
     *
     * @author Luke Taylor
     * @author Rob Winch
     * @since 3.2
     */
    public class ConcurrentSingleSessionAuthenticationStrategy implements
            SessionAuthenticationStrategy {
        private SessionRegistry sessionRegistry;

        /**
         * @param sessionRegistry the session registry which should be updated when the
         * authenticated session is changed.
         */
        public ConcurrentSingleSessionAuthenticationStrategy(SessionRegistry sessionRegistry) {
            Assert.notNull(sessionRegistry, "SessionRegistry cannot be null");
            this.sessionRegistry = sessionRegistry;
        }
        /**
         * In addition to the steps from the superclass, the sessionRegistry will be removing
         * with the new session information.
         */
        public void onAuthentication(Authentication authentication,
                HttpServletRequest request, HttpServletResponse response) {

            def sessions = sessionRegistry.getAllSessions(
                    authentication.getPrincipal(), false);

            def principals = sessionRegistry.getAllPrincipals()
            sessions.each{
                if(it.principal == authentication.getPrincipal()){
                    it.expireNow()
                }
            }


        }
    }

In resources.groovy:

    import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
    import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
    import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
    import org.springframework.security.core.session.SessionRegistryImpl;
    import com.myapp.test.ConcurrentSingleSessionAuthenticationStrategy;
    import org.springframework.security.web.session.ConcurrentSessionFilter
    // Place your Spring DSL code here
    beans = {
            sessionRegistry(SessionRegistryImpl)
            //I see you did not have this. Very dangerous!
            sessionFixationProtectionStrategy(SessionFixationProtectionStrategy){
                migrateSessionAttributes = true
                alwaysCreateSession = true
            }
            //Initiate the bean
            concurrentSingleSessionAuthenticationStrategy(ConcurrentSingleSessionAuthenticationStrategy,ref('sessionRegistry'))
            registerSessionAuthenticationStrategy(RegisterSessionAuthenticationStrategy,ref('sessionRegistry'))
            sessionAuthenticationStrategy(CompositeSessionAuthenticationStrategy,[ref('concurrentSingleSessionAuthenticationStrategy'),ref('sessionFixationProtectionStrategy'),ref('registerSessionAuthenticationStrategy')])
            concurrentSessionFilter(ConcurrentSessionFilter,ref('sessionRegistry'))
    }

In config, finally add this line:

grails.plugin.springsecurity.filterChain.filterNames = [ 'securityContextPersistenceFilter', 'logoutFilter', 'concurrentSessionFilter', 'rememberMeAuthenticationFilter', 'anonymousAuthenticationFilter', 'exceptionTranslationFilter', 'filterInvocationInterceptor' ]

Hope this helps.

这篇关于grails 3并发会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆