grails - 使用用户组和角色时 Grails/Spring Security 中的错误 - 无法进行身份验证

标签 grails plugins spring-security

我想我在 Grails Spring Security 3.1.1 和最新的 Grails 3.2.6 中发现了一个错误。
我已经安装了 Spring Security 插件。
从命令行控制台我做了以下:

grails s2-quickstart org.softwood.security User Role --groupClassName=UserGroup
创建一个用户、角色和 UserGroup 表,因为我想使用将角色分配给组功能。然后我配置了域类,并在 Bootstrap 中添加了一些用户来测试它,如下所示:
def loadSecurityUserAndRoles () {
    //plugin requires ROLE_ prefix see section 4.2/p18

    Role adminRole = new Role(authority: 'ROLE_ADMIN').save(failOnError:true)
    Role userRole = new Role(authority: 'ROLE_USER').save(failOnError:true)
    Role xtraRole = new Role(authority: 'ROLE_XTRA').save(failOnError:true)
    UserGroup adminGroup = new UserGroup (name:"GROUP_ADMIN").save(failOnError:true)
    UserGroup userGroup = new UserGroup (name:"GROUP_USERS").save(failOnError:true)

    User userWill = new User(username: 'will', password: 'password').save(failOnError:true)
    User userMaz = new User(username: 'maz', password: 'password').save(failOnError:true)
    User userMeg = new User(username: 'meg', password: 'password').save(failOnError:true)

    //give adminGroup admin and user roles
    UserGroupToRole sgr = UserGroupToRole.create(adminGroup, adminRole)
    sgr = UserGroupToRole.create(adminGroup, userRole)

    sgr = UserGroupToRole.create(userGroup, userRole)

    assert UserGroupToRole.count() == 3

    def auth2 = adminGroup.getAuthorities()
    println "adminGroup authorities returned $auth2 "

    //assign test user to adminGroup, and maz+meg to user group, inherit all group roles
    UserToUserGroup su2g = UserToUserGroup.create (userWill, adminGroup, true)
    su2g = UserToUserGroup.create (userMaz, userGroup, true)
    su2g = UserToUserGroup.create (userMeg, userGroup, true)

    //assign individual 'xtra' role to user
    UserToRole sxtra = UserToRole.create(userWill, xtraRole, true)
    assert UserToRole.count() == 1

    def auth = userWill.getAuthorities()
    assert auth.collect{it.authority}.sort() == ['ROLE_ADMIN', 'ROLE_USER', 'ROLE_XTRA']
    println "userWill authorities returned $auth "

    def mazAuth = userMaz.getAuthorities()
    def megAuth = userMeg.getAuthorities()
    println "user authorities returned maz: '$mazAuth', and meg: '$megAuth' "


    def groups = userWill.getUserGroups()
    assert groups.collect{it.name}.sort() == ['GROUP_ADMIN']

    assert UserGroup.count() == 2
    assert User.count() == 3
    assert Role.count() == 3
    assert UserToUserGroup.count() == 3
    assert UserGroupToRole.count() == 3
    assert UserToRole.count() == 1

}
这一切似乎都像 id 期望的那样工作,当我断言 <userInst>.getAuthorities() 时,基本断言为每个用户返回正确数量的角色:
然后我设置了一个带有开放操作的 Controller secureTest 并保护了一个
class SecureTestController {

    def index() {
        render "hello Will you passed the permit_any"
    }

    @Secured ('ROLE_ADMIN')
    def secure () {
        render "hello Will you passed the ROLE_ADMIN"

    }
}
我运行应用程序 - 它启动,我将浏览器指向 secureTest/index - 作为打开的 url 工作正常。
当我将浏览器指向secureTest/secure 时,它​​会抛出默认登录页面。我填写遗嘱/密码,它会抛出堆栈跟踪并且无法登录。
我认为该跟踪的关键部分在这里:
Caused by: groovy.lang.MissingPropertyException: No such property: authorities for class: org.softwood.security.Role
Possible solutions: authority
    at org.grails.datastore.gorm.GormInstanceApi.propertyMissing(GormInstanceApi.groovy:55)
    at org.grails.datastore.gorm.GormEntity$Trait$Helper.propertyMissing(GormEntity.groovy:57)
    at org.grails.datastore.gorm.GormEntity$Trait$Helper$propertyMissing$9.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
    at org.softwood.security.Role.propertyMissing(Role.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaClassImpl.invokeMissingProperty(MetaClassImpl.java:880)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1861)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3735)
    at org.softwood.security.Role.getProperty(Role.groovy)
    at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:172)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:456)
    at grails.plugin.springsecurity.userdetails.GormUserDetailsService$_loadAuthorities_closure2.doCall(GormUserDetailsService.groovy:92)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at groovy.lang.Closure.call(Closure.java:414)
    at groovy.lang.Closure.call(Closure.java:430)
我认为该方法在这里确实失败了(GormUserDetailsS​​ervice.groovy:92)。
当您单击该链接时,编辑器会将您带到插件中。
protected Collection<GrantedAuthority> loadAuthorities(user, String username, boolean loadRoles) {
    if (!loadRoles) {
        return []
    }

    def conf = SpringSecurityUtils.securityConfig

    String authoritiesPropertyName = conf.userLookup.authoritiesPropertyName
    String authorityPropertyName = conf.authority.nameField

    boolean useGroups = conf.useRoleGroups
    String authorityGroupPropertyName = conf.authority.groupAuthorityNameField

    Collection<?> userAuthorities = user."$authoritiesPropertyName"
    def authorities

    if (useGroups) {
        if (authorityGroupPropertyName) {
            authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }
        }
        else {
            log.warn 'Attempted to use group authorities, but the authority name field for the group class has not been defined.'
        }
    }
    else {
        authorities = userAuthorities.collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }
    }
    authorities ?: [NO_ROLE]
}
这里的关键部分是这个调用序列:
    if (useGroups) {
        if (authorityGroupPropertyName) {
            authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }
        }
useGroups 是真的。我有一个通过快速安装脚本在 application.groovy 文件中设置的 authorityGroupPropertyName:
grails.plugin.springsecurity.authority.groupAuthorityNameField = 'authorities'
所以上面的代码行调用:
userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique()
这将 role.authority 名称的 hashSet 作为字符串返回,而 flatten/unique 只是确保没有嵌套结构并且字符串是唯一的。到现在为止还挺好。
最后一点是我认为的错误。
<hashSet of role Names>.collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }
在此位中,对字符串集调用 collect 方法,但传递给“SimpleGrantedAuthority”的字符串应该只是字符串。相反,它的召唤
it."$authorityPropertyName" 
它是一个字符串并且没有这样的属性。
application.groovy 中设置的关键位是:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'org.softwood.security.User'
grails.plugin.springsecurity.userLookup.authoritiesPropertyName = 'authorities'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'org.softwood.security.UserToUserGroup'
grails.plugin.springsecurity.authority.className = 'org.softwood.security.Role'
grails.plugin.springsecurity.authority.groupAuthorityNameField = 'authorities' //'authority'
grails.plugin.springsecurity.useRoleGroups = true
如您所见,我尝试将权限更改为“权限”,因为这是角色类中的属性名称。这也因缺少属性消息而失败。
我认为这是一个错误,代码应该只是通过了“它”:
.collect {new SimpleGrantedAuthority(it)}
生成 <SimpleGrantedAuthority> 类型的 hashSet。
有没有其他人对 Spring Security 有这个问题?我不敢相信我是第一个摔倒它的人,或者也许没有人试图使用团体?

最佳答案

好的,就在我 sleep 之前 - 我将 GormUserDetailsS​​ervice 中的代码复制到我的 Bootstrap 中,这样我就可以在我自己的文件空间中展开扩展/播放。

我修改了 if block 并像这样展开

    if (useGroups) {
            if (authorityGroupPropertyName) {
                //userAuthorities returns Set<Role>
                println """ debug
authoritiesPropertyName = $authoritiesPropertyName
authorityPropertyName = $authorityPropertyName
authorityGroupPropertyName = $authorityGroupPropertyName
userAuthorities returns $userAuthorities of type ${userAuthorities.getClass()}

"""
                 def roles = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique()

                authorities = roles.collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }

我的调试字符串在控制台上显示
 debug
authoritiesPropertyName = authorities
authorityPropertyName = authority
authorityGroupPropertyName = authority
userAuthorities returns [Role(authority:ROLE_XTRA), Role(authority:ROLE_USER), Role(authority:ROLE_ADMIN)] of type class java.util.HashSet

返回到变量“角色”的第一个结果是字符串的 ArrayList(每个角色。授权名称实例。对于该用户具有正确的值,如在 userWill 的早期引导设置中。

下一个代码现在失败,因为我有一个字符串 ArrayList,它试图访问一个属性
 authorities = roles.collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }

失败了
groovy.lang.MissingPropertyException: No such property: authority for class: java.lang.String
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:458)
    at coffeeshopapp.BootStrap$_loadSecurityUserAndRoles_closure6.doCall(BootStrap.groovy:115)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at groovy.lang.Closure.call(Closure.java:414)
    at groovy.lang.Closure.call(Closure.java:430)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3170)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3140)
    at org.codehaus.groovy.runtime.dgm$66.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at coffeeshopapp.BootStrap.loadSecurityUserAndRoles(BootStrap.groovy:115)

无论我以哪种方式在原始源中剪切这条单行都是行不通的。原行再次读取
        authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }

如果它改为这样读取 - 代码将起作用
        authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it) }

v3.1.1插件中的代码肯定不能工作吗?

关于grails - 使用用户组和角色时 Grails/Spring Security 中的错误 - 无法进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42460249/

相关文章:

qt - 如何本地化 Qt qmldir 插件?

ide - 增量粘贴插件?

rest - 使用Grails配置CORS 3

Java - 我需要一个自定义 spring 过滤器,应在 http 响应后调用

amazon-web-services - DefaultHandshakeHandler 的 determineUser 未在生产服务器上调用

tomcat - Grails Enum 在 Jetty 上工作,在 Tomcat 上中断

grails - 有什么好的学习Grails的资源?

scala - 针对不同的启动器版本交叉构建 sbt 插件?

javascript - 不安全的 JavaScript 尝试使用框架访问

grails - 什么时候使用grassOn计算grails过滤器顺序