Grails spring security在向控制器操作发出ajax请求时出现403错误

Posted

技术标签:

【中文标题】Grails spring security在向控制器操作发出ajax请求时出现403错误【英文标题】:Grails spring security getting 403 error while making ajax request to controller action 【发布时间】:2016-01-09 12:57:15 【问题描述】:

这是我在 config.groovy 中的 grails.plugin.springsecurity.filterChain.chainMap

grails.plugin.springsecurity.filterChain.chainMap = [
//        '/api/v/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter,-basicAuthenticationFilter,-basicExceptionTranslationFilter',
        '/api/v/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter',
        '/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-apiAuthenticationFilter,-apiExceptionTranslationFilter',
        '/**': 'JOINED_FILTERS,-basicAuthenticationFilter,-basicExceptionTranslationFilter,-apiAuthenticationFilter,-apiExceptionTranslationFilter'
]

我制作 ajax 的控制器也有 permitAll 规则:

grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/':                              ['permitAll'],
'/index':                         ['permitAll'],
'/index.gsp':                     ['permitAll'],
'/assets/**':                     ['permitAll'],
'/**/js/**':                      ['permitAll'],
'/**/css/**':                     ['permitAll'],
'/**/images/**':                  ['permitAll'],
'/**/img/**':                     ['permitAll'],
'/**/favicon.ico':                ['permitAll'],
'/back/**':                       ['permitAll'],
'/lib/**':                        ['permitAll'],
'/ajax/dck/**':                   ['permitAll'],
'/api/**':                        ['permitAll'],
'/logout/**':                     ['permitAll'],
'/register/**':                   ['permitAll'],
'/webinar/test/**':               ['permitAll'],
'/i/**':                          ['permitAll'],
'/a/**':                          ['permitAll'],
'/hangout/**':                    ['permitAll'],
'/pusher/**':                     ['permitAll'],
'/go/**':                         ['permitAll'],
'/redactor/**':                   ['permitAll'],
'/bootstrap/**':                  ['permitAll'],
'/bootstrap-switch/**':           ['permitAll'],
'/js/**':                         ['permitAll'],
'/error/**':                      ['permitAll'],
'/integration/**':                ['permitAll']
]

网址是/integration/ajaxSaveIntegrationData,请求是http post。

spring 安全调试日志显示了下面这个 ajax 请求的日志:

2015-10-12 06:20:17,053Z DEBUG [http-bio-8443-exec-3]  Checking match of request : '/integrations/ajaxsaveintegrationdata'; against '/api/v/**'
 (SLF4JLog.java:debug:128) security.web.util.matcher.AntPathRequestMatcher 
2015-10-12 06:20:17,053Z DEBUG [http-bio-8443-exec-3]  Checking match of request : '/integrations/ajaxsaveintegrationdata'; against '/api/**'
 (SLF4JLog.java:debug:128) security.web.util.matcher.AntPathRequestMatcher 
2015-10-12 06:20:17,053Z DEBUG [http-bio-8443-exec-3]  Request '/integrations/ajaxsaveintegrationdata' matched by universal pattern '/**'
 (SLF4JLog.java:debug:128) security.web.util.matcher.AntPathRequestMatcher 
2015-10-12 06:20:17,053Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@963dd870: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@963dd870: Principal: rahulserver; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER, ROLE_WEBINAR, ROLE_API, ROLE_PREMIUM_PLAN, ROLE_API_USER'
 (SLF4JLog.java:debug:128) springframework.security.web.context.HttpSessionSecurityContextRepository 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 2 of 10 in additional filter chain; firing Filter: 'ApiAuthenticationFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 3 of 10 in additional filter chain; firing Filter: 'MutableLogoutFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 4 of 10 in additional filter chain; firing Filter: 'RequestHolderAuthenticationFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 5 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 6 of 10 in additional filter chain; firing Filter: 'GrailsRememberMeAuthenticationFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@963dd870: Principal: rahulserver; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER, ROLE_WEBINAR, ROLE_API, ROLE_PREMIUM_PLAN, ROLE_API_USER'
 (SLF4JLog.java:debug:128) plugin.springsecurity.web.filter.GrailsRememberMeAuthenticationFilter 
2015-10-12 06:20:17,054Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 7 of 10 in additional filter chain; firing Filter: 'GrailsAnonymousAuthenticationFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,055Z DEBUG [http-bio-8443-exec-3]  SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@963dd870: Principal: rahulserver; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER, ROLE_WEBINAR, ROLE_API, ROLE_PREMIUM_PLAN, ROLE_API_USER'
 (GrailsAnonymousAuthenticationFilter.java:applyAnonymousForThisRequest:67) plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter 
2015-10-12 06:20:17,058Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 8 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,058Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,058Z DEBUG [http-bio-8443-exec-3]  /integrations/ajaxSaveIntegrationData at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
 (SLF4JLog.java:debug:128) org.springframework.security.web.FilterChainProxy 
2015-10-12 06:20:17,060Z DEBUG [http-bio-8443-exec-3]  Secure object: FilterInvocation: URL: /integrations/ajaxSaveIntegrationData; Attributes: [_DENY_]
 (SLF4JLog.java:debug:128) security.web.access.intercept.FilterSecurityInterceptor 
2015-10-12 06:20:17,060Z DEBUG [http-bio-8443-exec-3]  Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@963dd870: Principal: rahulserver; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER, ROLE_WEBINAR, ROLE_API, ROLE_PREMIUM_PLAN, ROLE_API_USER
 (SLF4JLog.java:debug:128) security.web.access.intercept.FilterSecurityInterceptor 
2015-10-12 06:20:17,060Z DEBUG [http-bio-8443-exec-3]  getReachableGrantedAuthorities() - From the roles [ROLE_USER, ROLE_WEBINAR, ROLE_API, ROLE_PREMIUM_PLAN, ROLE_API_USER] one can reach [ROLE_PREMIUM_PLAN, ROLE_USER, ROLE_API, ROLE_API_USER, ROLE_WEBINAR] in zero or more steps.
 (SLF4JLog.java:debug:128) springframework.security.access.hierarchicalroles.RoleHierarchyImpl 
2015-10-12 06:20:17,060Z DEBUG [http-bio-8443-exec-3]  SecurityContextHolder now cleared, as request processing completed
 (SLF4JLog.java:debug:128) springframework.security.web.context.SecurityContextPersistenceFilter 
2015-10-12 06:20:17,061Z ERROR [http-bio-8443-exec-3]  Servlet.service() for servlet [default] in context with path [] threw exception [Filter execution threw an exception] with root cause
 (StandardWrapperValve.java:invoke:258) ContainerBase.[Tomcat].[localhost].[/].[default] java.lang.IllegalAccessError: tried to access method org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions()V from class grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager$$EPQsT6eI
    at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager$$EPQsT6eI.decide(AuthenticatedVetoableDecisionManager.java:43)
    at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager$$DPQsT6eI.decide(Unknown Source)
    at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.decide(AuthenticatedVetoableDecisionManager.java)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146)
    at grails.plugin.springsecurity.web.filter.GrailsRememberMeAuthenticationFilter.doFilter(GrailsRememberMeAuthenticationFilter.java)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
    at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:53)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:62)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
    at security.ApiAuthenticationFilter.doFilter(ApiAuthenticationFilter.groovy)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:69)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

控制器有permitAll:

@Secured(["permitAll"])
class IntegrationController 

那么为什么它通过 ajax 给我 403 错误?

【问题讨论】:

【参考方案1】:

将此添加到您的控制器代码中

static allowedMethods = [ajaxSaveIntegrationData : 'POST']

【讨论】:

以上是关于Grails spring security在向控制器操作发出ajax请求时出现403错误的主要内容,如果未能解决你的问题,请参考以下文章

Grails - 卸载 Spring Security Core

Grails - grails-spring-security-rest - 无法从 application.yml 加载 jwt 机密

grails-spring-security-rest 插件和悲观锁定

Grails + spring-security-core:用户登录后如何分配角色?

Grails Spring Security注释问题

Grails Spring Security 插件网址