遇到问题并认为它是grails spring security 3.1.1中的一个bug(?),以及最新的grails 3.2.6。
我已经安装了spring security插件。
从命令行控制台我做了以下
grails s2-quickstart org.softwood.security User Role --groupClassName=UserGroup
创建用户,角色和UserGroup表,因为我想使用分配角色到组功能。然后我将域类配置为tad,并在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
}
当我断言.getAuthorities()
时,这一切看起来都像id期望的那样工作,并且基本断言为每个用户返回正确数量的角色 然后,我设置了一个带有开放动作的控制器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 - 工作正常,因为打开网址
当我将浏览器指向secureTest / secure时,它会抛出默认登录页面。我填写will / password,它会抛出stacktrace而无法登录
该追踪的关键部分在这里我认为
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为true。我有一个通过快速安装脚本
在application.groovy文件中设置的authorityGroupPropertyNamegrails.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
你可以看到我试图将权限更改为'权限',因为它是角色类中的属性名称。失败的属性消息也
我认为这是一个错误,代码应该通过'it'
.collect {new SimpleGrantedAuthority(it)}
生成类型的hashSet。
有没有其他人有弹簧安全问题?我不能相信我是第一个失败的人,或者也许没有人试图使用团体,不确定
在我提出项目缺陷之前会很感激一些反馈 - 并弄清楚我是如何解决这个问题直到它'固定'
提前致谢
答案 0 :(得分:0)
好吧,就在我上床睡觉之前 - 我将代码从GormUserDetailsService中复制到我的bootstrap中,这样我就可以在我自己的文件空间中展开expand / play。
我修改了if块并像这样扩展了
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
返回到变量'roles'的第一个结果是String的StringList(每个role.authority名称实例。具有此用户的正确值,如在userWill的早期bootstrap设置中。
下一个代码现在失败了,因为我有一个StringList的字符串,它试图访问一个属性
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插件中的代码肯定无法正常工作吗?
答案 1 :(得分:0)
我也配置了用户角色和角色组,这就是我的工作方式:
在用户类中:
Set<Role> getAuthorities() {
RoleGroupRole.findAllByRoleGroup(this)*.role
}
def getAuthority() {
RoleGroupRole.withTransaction {
RoleGroupRole.findAllByRoleGroup(this)*.role.authority[0]
}
}
在RoleGroup.groovy中我有:(想想我改变了这些不确定的地方)
private void addAdminUser(String username) {
User adminUser = User.findByUsername(username)
if (!adminUser) {
User.withTransaction {
adminUser = new User(username: username, password: 'PASSWORD'
)
adminUser.save(flush: true)
}
}
def adminRole
Role.withTransaction {
adminRole= Role.findByAuthority('ROLE_ADMIN')
if (!adminRole) {
adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
UserRole.create adminUser, adminRole,true
}
}
def adminRoleGroup
RoleGroup.withTransaction {
adminRoleGroup = RoleGroup.findByName('ADMINS')
if (!adminRoleGroup) {
adminRoleGroup = new RoleGroup(name: 'ADMINS').save(flush: true)
}
}
UserRoleGroup.withTransaction {
def adminRoleGroupRole = RoleGroupRole.findByRole(adminRole)
if (!adminRoleGroupRole) {
adminRoleGroupRole = new RoleGroupRole(role: adminRole, roleGroup: adminRoleGroup).save(flush: true)
new UserRoleGroup(user: adminUser, roleGroup: adminRoleGroup).save(flush: true)
}
}
}
在我的引导程序中,这样的内容会创建绑定到角色和角色组的默认管理员帐户:
var genericType = typeof(MsAccessQueryBuilder<>);
var specificType = genericType.MakeGenericType(typeof(nEx));
var x = Activator.CreateInstance(specificType);
答案 2 :(得分:0)
好的vahid - 想想我已经剥了洋葱并找到了问题。
步骤1。回到开始并从头开始创建一个新项目,并在空项目中添加了grails-security插件。从grails控制台使用此按照oneline指南grails s2-quickstart org.softwood User Role --groupClassName=RoleGroup
这很有效,所以我把它产生的东西与我自己的东西进行了比较,并认为我理解问题出在哪里。
我的角色类与空测试一样 - 没有区别。
然后我进入了User类,不知怎的,我得到了getAuthorities()返回Set(这似乎是合理的,因为我的UserGroup中的getAuthorites()(又称为新开始时的RoleGroup)返回Set。并且基本用户/ Role返回Set
如果您生成仅包含User和Role的项目,则User.getAuthorities()将返回set。但是当使用组时,模板被更改并且返回了Set。
这种差异至关重要。因为调整其解引用策略的代码是在GormUserDetailsService.loadAuthorities()中的代码中,它无法看到它 - 请参阅我的调整版本ID试图修复...
if (useGroups) {
if (authorityGroupPropertyName) {
//authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it."$authorityPropertyName") }
//ww edit to stop gpf.. userAuthorties is Set<Role>, so first collect gets the names and produces ArrayList of stirng
//second collect builds the authorities as Set<SimpleGrantedAuthority>
authorities = userAuthorities.collect { it."$authorityGroupPropertyName" }.flatten().unique().collect { new SimpleGrantedAuthority(it) }
}
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") }
}
问题在于def authorities
变量会根据是否使用用户/角色或用户/组/角色模型而更改类型。
我陷入了中间,因为我试图使用组(默认分配模型)但允许单独的角色分配(个人授予角色,作为覆盖设施)。
当我读取User.authorities
属性时 - 我假设这将返回它与之链接的角色(通过组,并通过我的个人分配覆盖)(如在单个用户/角色模型中)。我在类用户
Set<Role> getAuthorities() {
//orig UserUserGroupBroken.findAllByUser(this)*.userGroup
Set<Role> individualRoles = UserToRole.findAllByUser(this)*.role
Set<UserGroup> groups = UserToUserGroup.findAllByUser(this)*.group
Set<Role> groupRoles = groups.collect{it.getAuthorities() }
Set<Role> aggregateRoles = new HashSet()
aggregateRoles.addAll (groupRoles.flatten())
aggregateRoles.addAll (individualRoles.flatten())
aggregateRoles
}
所以这一切似乎都是合理的并且做了我想要的(我的测试显示了通过叠加分配的正确角色)。但是,GormUserDetailsService并不期望这样,并且就像useGroups为真一样,它会取消引用两个集合以获取一个Set,并使用它来构建SimpleGrantedAuthority Set。
这是我对我想要做的事情的充实,它远远不同于假定的模型。
我会把它作为git网站上的建议,因为它会更清晰,更不透明,我认为你直觉地认为用户的authorities
属性会给你一个组。
现在只需要坚持使用基本的用户/组/角色模型并与之共存。