2015-08-09 45 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

相關問題