在ajax请求和超时会话期间,Grails没有响应401 [英] Grails isn't responding with a 401 during ajax request and timed out session
问题描述
我正在使用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 = {
}
}
这篇关于在ajax请求和超时会话期间,Grails没有响应401的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!