grails spring 安全角色和组

Posted

技术标签:

【中文标题】grails spring 安全角色和组【英文标题】:grails spring security role and group 【发布时间】: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) 如果是,我该怎么做?

【问题讨论】:

【参考方案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.collectit?.flatten() ?: oldRoles) as Set<Role>


List<String> getRoleNames() 
        (UserRoleGroup?.findAllByUser(this)?.roleGroup?.collectit.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; 身份验证仍将通过之前生成的实际角色名称进行。

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

这就是模型应该做的事情

【讨论】:

以上是关于grails spring 安全角色和组的主要内容,如果未能解决你的问题,请参考以下文章

Grails Spring 安全性

Grails + spring-security-core:用户登录后如何分配角色?

Grails、Spring Security 和 Angular JS - 如何保护 URL?

Grails Spring Security 查询没有特定角色的用户

Grails 和 Spring Security 插件:基于角色登录时重定向用户

Grails Spring Security Core 创建新用户