Grails 2.5.2 Spring Security自定义过滤器 - 错误无法设置请求属性 - 请求不再处于活动状态

时间:2016-10-19 09:58:24

标签: spring grails spring-security

我创建了一个自定义Spring安全过滤器来为我们的客户端make api调用执行基于HMAC令牌的auth。

以下是过滤器的样子:

class BqCustomTokenFilter extends GenericFilterBean implements ApplicationEventPublisherAware {


def authenticationManager
def customProvider

AuthenticationSuccessHandler authenticationSuccessHandler
AuthenticationFailureHandler authenticationFailureHandler

SessionAuthenticationStrategy sessionAuthenticationStrategy

ApplicationEventPublisher applicationEventPublisher


@Override
void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
        ServletException {

    HttpServletResponse response = (HttpServletResponse) resp
    /* wrap the request in order to read the inputstream multiple times */
    MultiReadHttpServletRequest request = new MultiReadHttpServletRequest((HttpServletRequest) req);

    if (!request.getRequestURI().startsWith('/api/')) {
        // Should not happen
        chain.doFilter(request, response)
        return
    }

    logger.trace("filter called from remote IP = ${req.remoteAddr} for URL ${request.getRequestURI()}")

    def requestBody = request.inputStream.getText()

    final AuthHeader authHeader = HmacUtil.getAuthHeader(request);

    if (authHeader == null) {
        // invalid authorization token
        logger.warn("Authorization header is missing");
        authenticationFailureHandler.onAuthenticationFailure(request.getRequest(), response, null)
        //unsuccessfulAuthentication(request, response, null)
        return
    }

    final String apiKey = authHeader.getApiKey();
    logger.trace("got request for apiKey = ${apiKey}")

    if (apiKey) {
        def myAuth = new BqAuthenticationToken(
                credentials: apiKey,
                authHeader: authHeader,
                payload: requestBody,
                requestDetails: [
                        scheme     : request.getScheme(),
                        host       : request.getServerName() + ":" + request.getServerPort(),
                        method     : request.getMethod(),
                        resource   : request.getRequestURI(),
                        contentType: request.contentType,
                        date1      : request.getHeader(HttpHeaders.DATE)

                ],
                authenticated: false
        )

        try {
            myAuth = authenticationManager.authenticate(myAuth)
            if (!myAuth.authenticated) {
                logger.warn("Authorization header does not match", ex)
                //unsuccessfulAuthentication(request, response, ex)
                //return
                logger.warn("Could not authenticate")
                SecurityContextHolder.clearContext()
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
                return
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Successfully Authenticated!!")
            }
            sessionAuthenticationStrategy.onAuthentication(myAuth, request, response)

        } catch (BadCredentialsException | Exception ex) {
            logger.warn("Authorization header does not match", ex)
            //unsuccessfulAuthentication(request, response, ex)
            //return
            logger.warn("Could not authenticate")
            SecurityContextHolder.clearContext()
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
            //respo.setStatus(statuscode)
            //authenticationFailureHandler.onAuthenticationFailure((HttpServletRequest) request, response, ex)
        }

        try {
            chain.doFilter(request, response)
            return
        } catch (IllegalStateException ex) {
            logger.warn("=====> IllegalStateException", ex)
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED)
        }
    } else {
        logger.warn("No API Key found in Request")
        SecurityContextHolder.clearContext()
        authenticationFailureHandler.onAuthenticationFailure((HttpServletRequest) request, response, null)
    }
}

void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    this.applicationEventPublisher = applicationEventPublisher
}

}

resources.groovy

sessionAuthenticationStrategy(NullAuthenticatedSessionStrategy)

bqCustomTokenFilter(com.bq.security.client.BqCustomTokenFilter) {
    authenticationManager = ref("authenticationManager")
    customProvider = ref("bqTokenAuthenticationProvider")
    authenticationSuccessHandler = ref('authenticationSuccessHandler')
    authenticationFailureHandler = ref('authenticationFailureHandler')
    sessionAuthenticationStrategy = ref('sessionAuthenticationStrategy')
}

Config.groovy中

grails.plugin.springsecurity.providerNames = [
    'bqTokenAuthenticationProvider',
    'daoAuthenticationProvider',
    'anonymousAuthenticationProvider',
    'rememberMeAuthenticationProvider']
grails.plugin.springsecurity.filterChain.filterNames = [
    'securityContextPersistenceFilter',
    'logoutFilter',
    'authenticationProcessingFilter',
    'bqCustomTokenFilter',
    'concurrencyFilter',
    'switchUserProcessingFilter',
    'rememberMeAuthenticationFilter',
    'anonymousAuthenticationFilter',
    'exceptionTranslationFilter',
    'filterInvocationInterceptor',
]
grails.plugin.springsecurity.filterChain.chainMap = [
    '/api/**': 'bqCustomTokenFilter',
    '/**'    : 'JOINED_FILTERS,-bqCustomTokenFilter'
]

我还安装了multitenant-single-db插件。身份验证工作绝对正常但是,偶尔会出现以下错误:

2016-10-19 14:06:51,120 +0530 [http-nio-8080-exec-1] ERROR UrlMappingsFilter:213  - Error when matching URL mapping [/api/execution/updateResult]:Cannot set request attribute - request is not active anymore!
java.lang.IllegalStateException: Cannot set request attribute - request is not active anymore!
at grails.plugin.multitenant.core.servlet.CurrentTenantServletFilter.doFilter(CurrentTenantServletFilter.java:53)
at com.bq.security.client.BqCustomTokenFilter$$EQ0438yG.doFilter(BqCustomTokenFilter.groovy:142)
at grails.plugin.springsecurity.web.filter.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:102)
at grails.plugin.springsecurity.web.filter.DebugFilter.doFilter(DebugFilter.java:69)
at com.brandseye.cors.CorsFilter.doFilter(CorsFilter.java:100)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

这通常发生在客户经常发送帖子请求时。由于我在客户端内置了重试逻辑,因此工作正常,但这种异常非常烦人。 非常感谢任何帮助。

0 个答案:

没有答案