Grails 在 ajax 请求和超时会话期间没有响应 401 [英] Grails isn't responding with a 401 during ajax request and timed out session

查看:22
本文介绍了Grails 在 ajax 请求和超时会话期间没有响应 401的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 grails 与 spring security 和 angularjs 一起使用.当用户会话过期并且用户单击页面上的 ajax 操作而不是响应 401 时,应用程序尝试重定向到登录页面,而原始 ajax 操作没有响应.

I'm using grails along with spring security and angularjs. When a user session has expired and the user clicks an ajax action on the page, rather than respond with a 401, the application attempts to redirect to the login page which no response from the original ajax action.

我仍在使用传统的登录页面,我的一些应用程序仍然有一些传统的页面链接,因此当会话过期并且用户单击页面链接时,我想重定向到登录页面.

I'm still using a traditional login page and some my application still has some traditional page links, so when a session has expired and a user clicks a page link, I would like to redirect to the login page.

如果用户单击 ajax 请求,我希望得到 401 响应而不是重定向的 html 响应,以便我可以在我的 javascript 中进行重定向.

If a user clicks on an ajax request, I would like to get a 401 response rather than the redirected html response so that I can do a redirect in my javascript.

我有以下配置设置.

grails.plugin.springsecurity.providerNames = ['hriLoginClientAuthenticationProvider']
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.failureHandler.defaultFailureUrl = '/login?error=1'
grails.plugin.springsecurity.auth.loginFormUrl = '/login'
grails.plugin.springsecurity.logout.postOnly = false

我需要做什么才能让ajax请求不重定向到登录页面?

What do I need to do to get ajax request to not redirect to the login page?

推荐答案

我遇到了类似的问题,并在过滤器链中实现了一个过滤器来检测 AJAX 请求并使用自定义的 HTTP 状态进行响应(您可以更改它如果您愿意,可以转到 401).

I've run into a similar issue and have implemented a filter in the filter chain to detect AJAX requests and respond with a customized HTTP status (you can change it to 401 if you like).

基本上分为三个部分.第一个,是过滤器.它是一个 servlet 过滤器,检查请求以及会话中的身份验证状态.其次,将过滤器定义为 Resources.groovy 中应用程序上下文中的 bean.最后,将它插入到 Spring Security 过滤器链中,这是我在 Bootstrap.groovy 中完成的.

Basically there are three parts to this. The first, is the filter. It's a servlet filter and examines the request as well as the state of the authentication in the session. Second, defining the filter as a bean within the application context in Resources.groovy. Finally, inserting it into the Spring Security filter chain, which I've done in Bootstrap.groovy.

现在我将带您完成此操作.

I'll walk you through this now.

首先是servlet过滤器(在src/java下)

First the servlet filter (under src/java)

package com.xyz.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.security.web.util.ThrowableCauseExtractor;
import org.springframework.web.filter.GenericFilterBean;

public class AjaxTimeoutRedirectFilter extends GenericFilterBean {

    // private static final Logger logger =
    // LoggerFactory.getLogger(AjaxTimeoutRedirectFilter.class);

    private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
    private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();

    private int customSessionExpiredErrorCode = 901;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);

            // logger.debug("Chain processed normally");
        } catch (IOException ex) {
            throw ex;
        } catch (Exception ex) {
            Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
            RuntimeException ase = (AuthenticationException) throwableAnalyzer
                    .getFirstThrowableOfType(AuthenticationException.class,
                            causeChain);

            if (ase == null) {
                ase = (AccessDeniedException) throwableAnalyzer
                        .getFirstThrowableOfType(AccessDeniedException.class,
                                causeChain);
            }

            if (ase != null) {
                if (ase instanceof AuthenticationException) {
                    throw ase;
                } else if (ase instanceof AccessDeniedException) {

                    if (authenticationTrustResolver
                            .isAnonymous(SecurityContextHolder.getContext()
                                    .getAuthentication())) {
                        // logger.info("User session expired or not logged in yet");
                        String ajaxHeader = ((HttpServletRequest) request)
                                .getHeader("X-Requested-With");

                        if ("XMLHttpRequest".equals(ajaxHeader)) {
                            // logger.info("Ajax call detected, send {} error code",
                            // this.customSessionExpiredErrorCode);
                            HttpServletResponse resp = (HttpServletResponse) response;
                            resp.sendError(this.customSessionExpiredErrorCode);
                        } else {
                            // logger.info("Redirect to login page");
                            throw ase;
                        }
                    } else {
                        throw ase;
                    }
                }
            }

        }
    }

    private static final class DefaultThrowableAnalyzer extends
            ThrowableAnalyzer {
        /**
         * @see org.springframework.security.web.util.ThrowableAnalyzer#initExtractorMap()
         */
        protected void initExtractorMap() {
            super.initExtractorMap();

            registerExtractor(ServletException.class,
                    new ThrowableCauseExtractor() {
                        public Throwable extractCause(Throwable throwable) {
                            ThrowableAnalyzer.verifyThrowableHierarchy(
                                    throwable, ServletException.class);
                            return ((ServletException) throwable)
                                    .getRootCause();
                        }
                    });
        }

    }

    public void setCustomSessionExpiredErrorCode(
            int customSessionExpiredErrorCode) {
        this.customSessionExpiredErrorCode = customSessionExpiredErrorCode;
    }
}

其次,在Resources.groovy

beans = {
    ajaxTimeoutRedirectFilter(com.xyz.security.AjaxTimeoutRedirectFilter)
}

最后,将过滤器放入 Spring Security 过滤器链中(为此我使用了 BootStrap.groovy)

And finally, getting the filter into the Spring Security filter chain (I used BootStrap.groovy for this)

import grails.plugin.springsecurity.SecurityFilterPosition
import grails.plugin.springsecurity.SpringSecurityUtils
class BootStrap {

    def init = { servletContext ->

        SpringSecurityUtils.clientRegisterFilter('ajaxTimeoutRedirectFilter', SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order + 10)

    }
    def destroy = {
    }
}

这篇关于Grails 在 ajax 请求和超时会话期间没有响应 401的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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