Grails,Spring Security Rest Plugin,无法在null对象上调用方法loadUserByToken()

时间:2016-07-12 06:20:56

标签: grails spring-security spring-security-rest

我正在使用Grails框架(2.5.0)中的Spring Security Plugin(2.0.0)和Spring Authentication Rest Plugin(1.5.3)尝试基于实现令牌的身份验证。我将标题字段“x-auth-token”设置为token并发布到目标控制器URL。但是,IDE(Intellij IDEA)会弹出此错误消息

| Error 2016-07-12 15:58:27,864 [http-bio-8080-exec-10] ERROR [/hello_world].
[default]  - Servlet.service() for servlet [default] in context with path [/hello_world] threw exception
Message: Cannot invoke method loadUserByToken() on null object
Line | Method
->>   55 | authenticate in grails.plugin.springsecurity.rest.RestAuthenticationProvider
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     75 | doFilter     in grails.plugin.springsecurity.rest.RestTokenValidationFilter
|     53 | doFilter . . in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|    143 | doFilter     in grails.plugin.springsecurity.rest.RestAuthenticationFilter
|     62 | doFilter . . in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|     80 | doFilter     in grails.plugin.springsecurity.rest.RestLogoutFilter
|     59 | doFilter . . in grails.plugin.springsecurity.web.SecurityRequestHolderFilter
|     82 | doFilter     in com.brandseye.cors.CorsFilter
|   1142 | runWorker .  in java.util.concurrent.ThreadPoolExecutor
|    617 | run          in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run . . . .  in java.lang.Thread

我检查了这个loadUserByToken()方法,并在tokenStorageService上调用它。我不知道为什么这个tokenStorageService是null对象。 Spring Security和Spring Security Plugin配置如下:

Config.groovy中

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'hello_world.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'hello_world.UserRole'
grails.plugin.springsecurity.authority.className = 'hello_world.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    '/':                ['permitAll'],
    '/index':           ['permitAll'],
    '/index.gsp':       ['permitAll'],
    '/assets/**':       ['permitAll'],
    '/**/js/**':        ['permitAll'],
    '/**/css/**':       ['permitAll'],
    '/**/images/**':    ['permitAll'],
    '/**/favicon.ico':  ['permitAll'],
    '/api/login':       ['permitAll']
]

grails {
    plugin {
        springsecurity {

            filterChain.chainMap = [
                    '/api/guest/**': 'anonymousAuthenticationFilter,restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor',
                    '/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter',  // Stateless chain
                    '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'                                                                          // Traditional chain
            ]

            providerNames = ['restAuthenticationProvider','daoAuthenticationProvider', 'rememberMeAuthenticationProvider']

            auth.loginFormUrl = '/login/auth'

            useSecurityEventListener = true

            onAuthenticationSuccessEvent = { e, appCtx ->
                // handle AuthenticationSuccessEvent

                System.out.println("Authentication Succeeded");
            }

            onAuthenticationSwitchUserEvent = { e, appCtx ->
                // handle AuthenticationSwitchUserEvent
            }

            onAuthorizationEvent = { e, appCtx ->
                // handle AuthorizationEvent
            }

            onRestTokenCreationEvent = { e, appCtx ->

                System.out.println("Token Created")
            }

            apf {
                filterProcessesUrl = '/api/login'
                allowSessionCreation = false
//                usernamePropertyName = 'username'
//                passwordPropertyName = 'password'
            }

            rest {

                active = true

                login {
                    active = true
                    endpointUrl = '/api/login'
                    failureStatusCode = 401
                    useJsonCredentials = true
                    usernamePropertyName = 'username'
                    passwordPropertyName = 'password'
                }

                token {

                    validation {
                        active = true
                        endpointUrl = '/api/validate'
                        headerName = 'x-auth-token'
                        useBearerToken = false
                        tokenPropertyName = 'access_token'
                        enableAnonymousAccess = true
                    }

                    generation {
                        active = true
                        useSecureRandom = true
                        useUUID = false
                    }

                    rendering {
                        usernamePropertyName = 'username'
                        authoritiesPropertyName = 'roles'
                        tokenPropertyName = 'token'
                    }

                    storage {
                        active = true
                        useGorm = true

                        gorm {
                            tokenDomainClassName = 'hello_world.AuthenticationToken'
                            tokenValuePropertyName = 'tokenValue'
                            usernamePropertyName = 'username'
                        }
                    }
                }
            }
        }
    }
}

resources.groovy

import grails.plugin.springsecurity.rest.RestAuthenticationProvider
beans = {
    restAuthenticationProvider(RestAuthenticationProvider);
}

我检查了数据库,令牌存储在authentication_token表中。我是grails的新手,并且一直在寻找数小时而且根本没有任何线索。谁能帮我?非常感谢。

如果您还有其他需要,请告诉我。

1 个答案:

答案 0 :(得分:1)

对于有同样问题的人,经过多次尝试后,我终于弄明白了。似乎我不应该在resources.groovy中声明restAuthenticationProvider,并且不应该将restAuthenticationProvider添加到config.groovy中的grails.plugin.springsecurity.providerNames。 spring-security-core和spring-security-rest的完整配置如下:

Config.groovy中

grails {
    plugin {
        springsecurity {

            useSecurityEventListener = true

            filterChain {
                chainMap = [
                        '/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter',  // Stateless chain
                        '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'                                                                          // Traditional chain
                ]
            } //filterChain

            apf {
                filterProcessesUrl = '/api/login'
            } //apf

            rest {

                login {
                    active = true
                    useRequestParamsCredentials = false
                    useJsonCredentials = true
                    usernamePropertyName = 'j_username'
                    passwordPropertyName = 'j_password'
                    endpointUrl = '/api/login'
                } //login

                logout {

                } //logout

                token {

                    validation {
                        active = true
                        endpointUrl = '/api/validate'
                        useBearerToken = false
                        headername = 'X-Auth-Token'
                    } //validation

                    generation {
//                        active = true
//                        useSecureRandom = true;
//                        useUUID = false;
                    }

                    rendering {
                        usernamePropertyName = 'username'
                        authoritiesPropertyName = 'roles'
                        tokenPropertyName = 'token'
                    }

                    storage {
//                        useJWT = true;
                    } //storage
                } //token
            } //rest

            cors.headers = ['Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Auth-Token']
        } //springsecurity
    } //plugin
} //grails

您应该使用字段" j_username"以json格式发送用户名和密码。和" j_password"它将以json格式返回一个令牌。然后,在标题字段中发送请求以及此标记" X-Auth-Token"到你要查询的api。

有关初始化spring-security-core插件的信息,请参阅http://grails-plugins.github.io/grails-spring-security-core/v2/guide/single.html#tutorials

我的代码完整可以在github中找到:https://github.com/xixinhe/api_token_authentication

在运行我的代码之前,请安装oracle mysql 5.

如果我写的任何内容违反了堆栈溢出规则,请告诉我,我会改变。

我不是母语为英语的人,请原谅我蹩脚的英语。

谢谢,