Grails:运行ajax请求时用户注销

Posted

技术标签:

【中文标题】Grails:运行ajax请求时用户注销【英文标题】:Grails: User logs out while ajax request is running 【发布时间】:2014-07-31 00:46:31 【问题描述】:

有一个带有 Spring Security Core 插件 (v.2.0-RC2) 的 Grails (v.2.3.2) Web 应用程序。

我偶然发现了一个用户在后台运行 ajax 请求时注销的问题。

场景如下:

    用户请求网页 页面准备就绪后,我会触发 ajax 请求 在服务器端仍在处理 ajax 请求时用户注销

服务器端自然严重依赖当前用户,第三步app就崩溃了,因为当前用户突然消失,springSecurityService表示用户未登录。

这是我用来在UserService 中获取当前用户的代码。

public User getLoggedInUser() 
    if (!springSecurityService.isLoggedIn()) 
        return null
    

    User user = User.get(springSecurityService.getPrincipal().id)
    user

这会在用户注销之前正常返回当前用户,从而导致问题。

我想出了使UserService 有状态并将当前用户存储在单独字段中的想法。

static scope = 'request' // create a new instance for every request

private Long currentUserId = null

public User getLoggedInUser() 
    if (!currentUserId) 
        if (!springSecurityService.isLoggedIn()) 
            return null
        

        // Store the ID of the current user in the instance variable.
        currentUserId = springSecurityService.getPrincipal().id
    

    // Fetch and return the user.
    return User.get(currentUserId)

此外,我创建了一个新的Spring bean,它为我的UserService 定义了一个代理对象。

userServiceProxy(ScopedProxyFactoryBean) 
    targetBeanName = 'userService'
    proxyTargetClass = true

现在,这在大多数情况下都非常有效,但在没有 Web 请求存在时会失败。特别是在BootStrap.groovy,我使用我的应用程序的其他服务。

这是我收到的错误消息:

初始化应用程序时出错:创建名为“scopedTarget.userServiceProxy”的 bean 时出错:范围“请求”对当前线程无效;如果您打算从单例中引用它,请考虑为该 bean 定义一个作用域代理;嵌套异常是 java.lang.IllegalStateException:未找到线程绑定请求:您是指实际 Web 请求之外的请求属性,还是在原始接收线程之外处理请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,请使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。

关于如何解决此问题的任何建议?

【问题讨论】:

【参考方案1】:

经过一番调查和大量脏话,终于找到了解决方案。

这是我在BootStrap.groovy 中用来模拟正在进行的网络请求的代码。

class BootStrap 

    def init =  ServletContext servletContext ->

        // Mock request and response.
        HttpServletRequest request = new MockHttpServletRequest(servletContext)
        HttpServletResponse response = new MockHttpServletResponse()

        // Now store them in the current thread.
        GrailsWebRequest grailsRequest = new GrailsWebRequest(request, response, servletContext)
        WebUtils.storeGrailsWebRequest(grailsRequest)

        /**
         * Perform whatever you need to do that requires an active web request.
         */

    

【讨论】:

以上是关于Grails:运行ajax请求时用户注销的主要内容,如果未能解决你的问题,请参考以下文章

在 grails 控制器中识别 ajax 请求或浏览器请求

Ajax PUT 请求导致 Rails 应用程序注销。为啥?

每当进行 AJAX POST 时,Laravel 4 应用程序都会将用户注销

Spring Security 3 - Ajax 注销

ajax请求在spring security中被拒绝,Grails

Grails:在服务器端检测请求中止(ajax,escape,reload)