2015-08-09 42 views
1

使用Grails spring security REST(其本身使用Grails Spring Security Core)我已生成User,,UserRole类。Grails Spring Security查询不具有某种作用的用户

用户:

class User extends DomainBase{ 

    transient springSecurityService 

    String username 
    String password 
    String firstName 
    String lastNameOrTitle 
    String email 
    boolean showEmail 
    String phoneNumber 
    boolean enabled = true 
    boolean accountExpired 
    boolean accountLocked 
    boolean passwordExpired 

    static transients = ['springSecurityService'] 

    static hasMany = [ 
      roles: Role, 
      ratings: Rating, 
      favorites: Favorite 
    ] 

    static constraints = { 
     username blank: false, unique: true 
     password blank: false 
     firstName nullable: true, blank: false 
     lastNameOrTitle nullable: false, blank: false 
     email nullable: false, blank: false 
     phoneNumber nullable: true 
    } 

    static mapping = { 
     DomainUtil.inheritDomainMappingFrom(DomainBase, delegate) 
     id column: 'user_id', generator: 'sequence', params: [sequence: 'user_seq'] 
     username column: 'username' 
     password column: 'password' 
     enabled column: 'enabled' 
     accountExpired column: 'account_expired' 
     accountLocked column: 'account_locked' 
     passwordExpired column: 'password_expired' 
     roles joinTable: [ 
       name: 'user_role', 
       column: 'role_id', 
       key: 'user_id'] 
    } 

    Set<Role> getAuthorities() { 
//  UserRole.findAllByUser(this).collect { it.role } 
//  userRoles.collect { it.role } 
     this.roles 
    } 

    def beforeInsert() { 
     encodePassword() 
    } 

    def beforeUpdate() { 
     super.beforeUpdate() 
     if (isDirty('password')) { 
      encodePassword() 
     } 
    } 

    protected void encodePassword() { 
     password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password 
    } 
} 

角色:

class Role { 

    String authority 

    static mapping = { 
     cache true 
     id column: 'role_id', generator: 'sequence', params: [sequence: 'role_seq'] 
     authority column: 'authority' 
    } 

    static constraints = { 
     authority blank: false, unique: true 
    } 
} 

的UserRole:

class UserRole implements Serializable { 

    private static final long serialVersionUID = 1 

    static belongsTo = [ 
      user: User, 
      role: Role 
    ] 
// User user 
// Role role 

    boolean equals(other) { 
     if (!(other instanceof UserRole)) { 
      return false 
     } 

     other.user?.id == user?.id && 
       other.role?.id == role?.id 
    } 

    int hashCode() { 
     def builder = new HashCodeBuilder() 
     if (user) builder.append(user.id) 
     if (role) builder.append(role.id) 
     builder.toHashCode() 
    } 

    static UserRole get(long userId, long roleId) { 
     UserRole.where { 
      user == User.load(userId) && 
        role == Role.load(roleId) 
     }.get() 
    } 

    static boolean exists(long userId, long roleId) { 
     UserRole.where { 
      user == User.load(userId) && 
        role == Role.load(roleId) 
     }.count() > 0 
    } 

    static UserRole create(User user, Role role, boolean flush = false) { 
     def instance = new UserRole(user: user, role: role) 
     instance.save(flush: flush, insert: true) 
     instance 
    } 

    static boolean remove(User u, Role r, boolean flush = false) { 
     if (u == null || r == null) return false 

     int rowCount = UserRole.where { 
      user == User.load(u.id) && 
        role == Role.load(r.id) 
     }.deleteAll() 

     if (flush) { 
      UserRole.withSession { it.flush() } 
     } 

     rowCount > 0 
    } 

    static void removeAll(User u, boolean flush = false) { 
     if (u == null) return 

     UserRole.where { 
      user == User.load(u.id) 
     }.deleteAll() 

     if (flush) { 
      UserRole.withSession { it.flush() } 
     } 
    } 

    static void removeAll(Role r, boolean flush = false) { 
     if (r == null) return 

     UserRole.where { 
      role == Role.load(r.id) 
     }.deleteAll() 

     if (flush) { 
      UserRole.withSession { it.flush() } 
     } 
    } 

    static constraints = { 
     role validator: { Role r, UserRole ur -> 
      if (ur.user == null) return 
      boolean existing = false 
      UserRole.withNewSession { 
       existing = UserRole.exists(ur.user.id, r.id) 
      } 
      if (existing) { 
       return 'userRole.exists' 
      } 
     } 
    } 

    static mapping = { 
     id composite: ['role', 'user'] 
     version false 
    } 
} 

现在我想创建一个管理区域,其中管理员可以修改/启用用户帐户,但可不要触摸其他管理员,因此我决定创建一个可分页的查询,只选择那些不用的用户具有ROLE_ADMIN角色,因为管理员具有ROLE_USERROLE_ADMIN角色。

如可以从上面的代码中可以看出,我已经修改了默认生成的代码比特并添加了joinTableUser类代替hasMany: [roles:UserRole]或将其保持在默认,但无任何作用的引用。造成这种变化的原因是因为在查询UserRole时,我偶尔会得到重复的内容,导致分页困难。

所以在这个当前的设置下,我设法创建了两个查询,它们只允许我提取没有管理员角色的用户。

def rolesToIgnore = ["ROLE_ADMIN"] 
def userIdsWithGivenRoles = User.createCriteria().list() { 
    projections { 
     property "id" 
    } 
    roles { 
     'in' "authority", rolesToIgnore 
    } 
} 

def usersWithoutGivenRoles = User.createCriteria().list(max: 10, offset: 0) { 
    not { 
     'in' "id", userIdsWithGivenRoles 
    } 
} 

首先查询获取它们具有ROLE_ADMIN角色的所有用户ID的列表,然后第二个查询获取所有的ID是不是在前面的列表中的用户。

这个工程,是可分页,然而困扰我的原因有两个:

  1. joinTable上的用户似乎只是“恶心”给我。为什么使用joinTable当我已经有一个特定的类为此目的UserRole,但是这个类是更难以查询,我害怕映射Role映射Role可能的开销User即使我只需要User
  2. 有两个查询,只有第二个可以分页。

所以我的问题是: 有没有建立一个查询获取不包含某些角色(不包括数据库改制成,每一个用户只有一个角色的金字塔角色系统)用户带来更优化的方式?

有两个查询是绝对必要的吗?我试图构造一个纯粹的SQL查询,我不能没有子查询。

回答

0

如果您的UserRole用户和角色性能而不是属于关联,像这样:

class UserRole implements Serializable { 

    private static final long serialVersionUID = 1 

    User user 
    Role role 
    ... 
} 

然后,你可以这样做:

def rolesToIgnore = ["ROLE_ADMIN"] 

def userIdsWithGivenRoles = UserRole.where { 
    role.authority in rolesToIgnore 
}.list().collect { it.user.id }.unique() 

def userIdsWithoutGivenRoles = UserRole.where { 
    !(role.authority in rolesToIgnore) 
}.list().collect { it.user.id }.unique() 

我吮吸预测,所以我删除重复与唯一()。

的SQL等价物:

SELECT DISTINCT ur.user_id 
FROM user_role AS ur INNER JOIN role AS r 
     ON ur.authority_id = r.id 
WHERE r.authority IN ('ROLE_ADMIN'); 

SELECT DISTINCT ur.user_id 
FROM user_role AS ur INNER JOIN role AS r 
     ON ur.authority_id = r.id 
WHERE r.authority NOT IN ('ROLE_ADMIN'); 
0

你可以做类似的东西:

return UserRole.createCriteria().list { 
    distinct('user') 
    user { 
     ne("enabled", false) 
    } 
    or { 
     user { 
      eq('id', springSecurityService.currentUser.id) 
     } 
     role { 
      not { 
       'in'('authority', ['ADMIN', 'EXECUTIVE']) 
      } 
     } 
    } 
} 

随着distinct('user')你才会得到Users

相关问题