【问题标题】:grails spring security role and groupgrails spring 安全角色和组
【发布时间】:2016-03-14 21:59:41
【问题描述】:

我已将 spring 安全配置为与组一起使用。

我使用这个 scipt 创建域类:

grails s2-quickstart com.yourapp User Role --groupClassName=RoleGroup

我假设一个用户可以有很多组,而一个组可以有很多角色

这是 User 类中生成的方法的样子:

Set<RoleGroup> getAuthorities() {
    UserRoleGroup.findAllByUser(this).collect { it.roleGroup }
}

但是现在我看到脚本还创建了一个名为 UserRole 的类,它是用户和角色之间的关联。那么一个用户也可以直接拥有多个角色?

我试过了,它保存在数据库中。我修改了这样的方法:

def getAuthorities() {
    def authorities = UserRoleGroup.findAllByUser(this).collect { it.roleGroup }

    authorities.addAll(UserRole.findAllByUser(this).collect { it.role })
    return authorities
}

现在,当我在用户 角色关联的数据库中创建一个条目时。我不能再登录了。我收到 spring security 的默认消息,基本上说没有找到凭据。

当我手动删除条目时,我可以再次登录。我认为这是因为该方法只返回 RoleGroup 对象。

我的问题是:

a) 我也可以在配置组后直接分配角色

b) 如果不是,为什么脚本要创建这个类

c) 如果是,我该怎么做?

【问题讨论】:

    标签: grails spring-security


    【解决方案1】:

    当您使用Groups 时,我认为您不会期望您将Role 直接分配给User

    Group 分配给用户,将Role 分配给Group

    我认为在“降级”您的应用程序时呈现的代码结构可能很有用

    仅使用 UserRoles,而不违反您当前的规则。

    【讨论】:

      【解决方案2】:

      这只是我的意见:脚本创建了 UserRole,因为它只是优化类,例如,如果您从 db 接收角色并试图找到一些用户休眠应该从代理接收所有用户。它只是优化类。如果您希望每个用户拥有一个角色,您可以在 UserRole.create() 中设置它 添加限制,它应该可以工作。希望你能理解我,我理解你是对的。祝你有美好的一天

      【讨论】:

        【解决方案3】:

        有点旧,但可能会为其他尝试团体的人提供帮助:

        在用户类中:

        Set<RoleGroup> getAuthorities() {
            (UserRoleGroup.findAllByUser(this) as List<UserRoleGroup>)*.roleGroup as Set<RoleGroup>
        }
        
        
        
        Set<Role> getRoles() {
          (UserRoleGroup?.findAllByUser(this)?.roleGroup?.authorities.collect{it}?.flatten() ?: oldRoles) as Set<Role>
        }
        
        List<String> getRoleNames() {
                (UserRoleGroup?.findAllByUser(this)?.roleGroup?.collect{it.authorities.authority}?.flatten()?: oldRoles.authority) as List<String>
        }
        
        //Above will look up from userRoleGroup roleGroup.authorities =  UserRole below
        Set<Role> getOldRoles() {
            (UserRole.findAllByUser(this) as List<Role>)*.role as Set<Role>
        }
        

        即使启用了组并针对旧的 oldRoles 方法进行身份验证,我也一直在使用角色:

        import grails.plugin.springsecurity.userdetails.GormUserDetailsService
        import grails.transaction.Transactional
        import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
        import org.springframework.security.core.Authentication
        import org.springframework.security.core.GrantedAuthority
        import org.springframework.security.core.authority.SimpleGrantedAuthority
        import org.springframework.security.core.context.SecurityContextHolder
        import org.springframework.security.core.userdetails.UserDetails
        import org.springframework.security.core.userdetails.UsernameNotFoundException
        
        class MySpringSecurityAuthenticator extends GormUserDetailsService{
        
            UserDetails loadUserByUsername(String username, boolean loadRoles)
                    throws UsernameNotFoundException {
                return loadUserByUsername(username)
            }
        
            @Transactional
            UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                //enable login with either username or password
                User user = User.find {
                    username == username || attributes.emailAddress == username || userCode == username
                }
                //if (!user) throw new UsernameNotFoundException('User not found', username)
                if (!user) throw new UsernameNotFoundException('User not found')
               return loadUserByUsername( user)
            }
            @Transactional
            UserDetails loadUserByUsername(User user) throws UsernameNotFoundException {
                if (!user) throw new UsernameNotFoundException('User not found')
               //UserDetails.withNewSession {
        //getAuthorities(user.oldRoles)
                    UserDetails userDetails = new org.springframework.security.core.userdetails.User(user.username, user.password,
                            user.enabled, !user.accountExpired, !user.passwordExpired, !user.accountLocked,getAuthoritiesFromGroup(user.authorities) )
                    Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities())
                    SecurityContextHolder.getContext().setAuthentication(authentication)
                    return userDetails
                //}
            }
        
            public static List<GrantedAuthority> getAuthoritiesFromGroup(Set<RoleGroup>  roles) {
                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>()
                roles?.each { role ->
                    println "-- role = ${role} vs ${role.getClass()}"
                    authorities.add(new SimpleGrantedAuthority(role.name))
                }
                return authorities
            }
            public static List<GrantedAuthority> getAuthorities(Set<Role> roles) {
                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>()
                roles?.each { role ->
                    println "-- role = ${role} vs ${role.getClass()}"
                    authorities.add(new SimpleGrantedAuthority(role.authority))
                }
                return authorities
            }
        }
        

        在我的 spring/resources.groovy 中:

        userDetailsService(MySpringSecurityAuthenticator){
            grailsApplication = ref('grailsApplication')
        }
        

        到目前为止,上面所做的是回到用户 ROLES 并通过..getAuthorities(user.oldRoles) 将它们添加到身份验证处理程序

        我现在已将上述方法更改为通过 getAuthoritiesFromGroup(user.authorities) 读取组名

        这只是解析组名,作为我正在使用的版本的一个副作用(效果)还必须包含单词 ROLE_GROUPNAME

        所以现在如果创建

        @Transactional
        def grantPermission(User user, String  role='ROLE_ADMIN', String group='ROLE_SUPERGROUP') {
            def adminRole = Role.findByAuthority(role)
            if (!adminRole) {
                adminRole = new Role(authority: role).save(flush: true)
        
            }
            UserRole.create user, adminRole, true
        
            def adminRoleGroup = RoleGroup.findByName(group)
            if (!adminRoleGroup) {
                adminRoleGroup = new RoleGroup(name: group).save(flush: true)
            }
            def adminRoleGroupRole = RoleGroupRole.findByRole(adminRole)
            if (!adminRoleGroupRole) {
                adminRoleGroupRole = new RoleGroupRole(role: adminRole, roleGroup: adminRoleGroup).save(flush: true)
            }
            def alreadyDone = UserRoleGroup.findByUserAndRoleGroup(user,adminRoleGroup)
            if (!alreadyDone) {
                new UserRoleGroup(user: user, roleGroup: adminRoleGroup).save(flush: true)
            }
        }
        

        我希望根据组名而不是用户角色进行身份验证,所以简而言之,我不得不将我的控制器更改为

        @Secured("hasAnyRole('ROLE_SUPERGROUP')")
        

        希望它是有意义的,应该是直截了当的,只是需要时间来理解这一切..

        在这一点上,我仍在玩弄,我不会将其用作具体答案,因为我有点想将其添加为我的权限,如果我愿意,我可以添加另一个钩子以进一步了解这些团体中的每一个以及其中的每个实际角色 - 不确定会产生什么 - 目前

        我想将其更改为 requestMaps 并将其移至 db 进行大量更改并将决定我是否应该恢复或使用我知道的组,这样我可以在控制器上配置更少的名称并依赖组名称。 .

        无论哪种方式,它都在这一切的背后,并在几年后为您提供一个清晰的想法,但可能对其他人派上用场

        更新 所以我决定去: ,getAuthorities(user.roles)

        上述代码中的Set&lt;Role&gt; getRoles() {方法

        原因很简单:

        results?.each {
                    it.user=User.get(it.id)
                    println "-- \n${it.id}:${it.user.roles} \n${it.id}:${it.user.oldRoles}"
        
        
        7:[Role(authority:ROLE_ADMIN), Role(authority:ROLE_ADMINAHHA)] 
        7:[Role(authority:ROLE_ADMIN)]
        

        如您所见,我使用 getOldRoles 添加了一个新用户我在 getRoles 上只看到 1 个角色我得到了 2 个角色..我确实添加了具有 2 个角色的用户..

        所以现在这将解析所有用户角色并将它们添加到List&lt;GrantedAuthority&gt; 身份验证仍将通过之前生成的实际角色名称进行。

        这只是意味着当我从用户禁用一个组时,这应该停止为该用户加载该权限..

        这就是模型应该做的事情

        【讨论】:

          猜你喜欢
          • 2012-04-08
          • 2015-10-28
          • 2015-09-04
          • 2011-05-30
          • 2011-01-01
          • 1970-01-01
          • 2015-05-22
          • 2019-08-20
          相关资源
          最近更新 更多