我想我在 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)
我认为该方法在这里确实失败了(GormUserDetailsService.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 之前 - 我将 GormUserDetailsService 中的代码复制到我的 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/