Grails SpringSecurity Spock功能测试UserDetailsService:在中找不到用户

Grails SpringSecurity Spock功能测试UserDetailsService:在中找不到用户,grails,spring-security,spock,grails-2.4,Grails,Spring Security,Spock,Grails 2.4,我使用的是Grails2.4.4,使用的是SpringSecurityCore2.0-RC4、SpringSecurityREST1.5.0.M1和功能性Spock0.7 我正在使用功能测试来测试我正在构建的RESTAPI的控制器。设置测试时,我创建一个用户,一个管理员角色,然后创建一个用户角色。当我检查用户是否已在spock功能测试中使用适当的凭据进行了持久化时,我发现一切正常 但是,在进行身份验证时,gormuserdeailsservice在调用User.findWhere(用户名:)时不

我使用的是Grails2.4.4,使用的是SpringSecurityCore2.0-RC4、SpringSecurityREST1.5.0.M1和功能性Spock0.7

我正在使用功能测试来测试我正在构建的RESTAPI的控制器。设置测试时,我创建一个
用户
,一个管理员
角色
,然后创建一个
用户角色
。当我检查
用户
是否已在spock功能测试中使用适当的凭据进行了持久化时,我发现一切正常

但是,在进行身份验证时,
gormuserdeailsservice
在调用
User.findWhere(用户名:)
时不会产生任何结果。具体方法来自
gormuserdetails服务
如下:

UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException {

    def conf = SpringSecurityUtils.securityConfig
    String userClassName = conf.userLookup.userDomainClassName
    def dc = grailsApplication.getDomainClass(userClassName)
    if (!dc) {
        throw new IllegalArgumentException("The specified user domain class '$userClassName' is not a domain class")
    }

    Class<?> User = dc.clazz

    User.withTransaction { status ->
        def user = User.findWhere((conf.userLookup.usernamePropertyName): username)
        if (!user) {
            log.warn "User not found: $username"
            throw new NoStackUsernameNotFoundException()
        }

        Collection<GrantedAuthority> authorities = loadAuthorities(user, username, loadRoles)
        createUserDetails user, authorities
    }
}
以下是
Config.groovy
中的spring安全设置:

grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.help.Person'
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'keyword'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.help.PersonRole'
grails.plugin.springsecurity.authority.className = 'com.help.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    '/':                              ['permitAll'],
    '/index':                         ['permitAll'],
    '/index.gsp':                     ['permitAll'],
    '/assets/**':                     ['permitAll'],
    '/**/js/**':                      ['permitAll'],
    '/**/css/**':                     ['permitAll'],
    '/**/images/**':                  ['permitAll'],
    '/**/favicon.ico':                ['permitAll'],
    '/dbconsole/**':                  ['ROLE_USER', 'ROLE_ADMIN']
]
grails.plugin.springsecurity.filterChain.chainMap = [
    '/v1/public/**': 'anonymousAuthenticationFilter,restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor',
    '/v1/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter',  // v1 rest api stateless
    '/api/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter',  // api utility methods stateless
    '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]

grails {
    plugin {
        springsecurity {
            rest {
                login.useJsonCredentials = true
                login.usernamePropertyName = "keyword"
                token {
                    rendering.usernamePropertyName = "keyword"
                    rendering.authoritiesPropertyName = "roles"
                    rendering.tokenPropertyName = "access_token"
                    validation.useBearerToken = true
                    validation.enableAnonymousAccess = true
                }
            }
        }
    }
}

事实证明,域类没有出现在服务器实例上的问题与功能测试中的服务器实例在单独的jvm(分叉jvm模式)上运行这一事实有关,因此所有需要通过远程发送的调用

我最终使用了远程控制插件,如下所示(回想一下我使用的是Grails2.4.4),如
BuildConfig.groovy
所示:

plugins {
    ...
    compile ":rest-client-builder:2.0.4-SNAPSHOT"
    compile ":remote-control:1.5"
    ...
}

我在向正确的URL发送请求时遇到了几个问题,这些问题在更新到最新版本后得到了解决,如上所示。另外,不要忘记将springsecurity核心设置配置为允许安装grails远程控制url。

当您不运行测试而只是运行应用程序时,这是否有效?您的Config.groovy中是否可能没有正确设置spring安全属性?你在功能测试中嘲笑什么?是的!当我运行应用程序时,效果很好。让我用springsecurity属性以及如何在功能测试中设置模拟来更新答案。我认为这与我不应该嘲笑GORM的某些方面有关,但我对spock或mocks了解不够。我可能错了,但我认为在功能测试期间创建mocks有点不寻常。我的理解是,这些测试应该更接近于集成测试,而不是单元测试,这意味着应用程序实际上是以嵌入式容器和数据源等启动的。这就是您可以向控制器发出HTTP请求的方式。试图将mocks变成这样似乎是不自然的。您仍然可以使用Spock,但我认为您应该使用数据源创建和清理数据,而不是试图模拟域。我明白了。您能否详细说明“使用数据源创建和清理数据”的含义?我应该扩展
IntegrationSpec
而不是
Specification
?我觉得我需要使用mock,因为我无法创建
Person
实例进行测试。非常感谢。当然,您可以使用IntegrationSpec。您正在对对象调用.save(),但看起来您模拟了这些对象,因此它们实际上不会保存到数据库中。因此,我希望您不要模拟这些,在测试结束时,在清理块中对创建的每个对象调用.delete()。我现在和Grails有点脱离接触,但我认为这仍然是正确的方法。嘿,你能告诉我你是如何配置spring安全内核以允许Grails远程控制url访问的吗?当然。在
Config.groovy
中,编写以下内容:
grails.plugin.springsecurity.controllernotations.staticRules=['/grails remote control':['permitAll']]
plugins {
    ...
    compile ":rest-client-builder:2.0.4-SNAPSHOT"
    compile ":remote-control:1.5"
    ...
}