简体   繁体   中英

Spring Security UI Grails only search/create/edit users for the admin?

I am currently working on a solution in Grails and I have installed the following security plugins:

  • Spring Security Core
  • Spring Security UI

I will basically have a solution with the following security structure:

  • Super Users
  • Admins(For different business areas)
  • Users (within the different business areas)

So basically I installed the Spring Security UI in order to allow the various Business Area Admins manage their own areas, they should be able to use the UI in order to allow them to search only for users in thier own area, create users in their own area and edit users only in their own area. However the spring security UI gives people who have access blanket access do anything.

I have added an extra field to the spring security domain model which is "Area", so I was thinking when the admin is searching for users they would only see users in the same area as them, when they create a user they can only do so for their own area and they can only edit users in their own area.

Below is some code that the spring security UI uses to search for the users, can I modify this in order to only return the users that are in the same area as the admin who is currently logged in? or is there a better way?

def userSearch = {

    boolean useOffset = params.containsKey('offset')
    setIfMissing 'max', 10, 100
    setIfMissing 'offset', 0

    def hql = new StringBuilder('FROM ').append(lookupUserClassName()).append(' u WHERE 1=1 ')
    def queryParams = [:]

    def userLookup = SpringSecurityUtils.securityConfig.userLookup
    String usernameFieldName = userLookup.usernamePropertyName

    for (name in [username: usernameFieldName]) {
        if (params[name.key]) {
            hql.append " AND LOWER(u.${name.value}) LIKE :${name.key}"
            queryParams[name.key] = params[name.key].toLowerCase() + '%'
        }
    }

    String enabledPropertyName = userLookup.enabledPropertyName
    String accountExpiredPropertyName = userLookup.accountExpiredPropertyName
    String accountLockedPropertyName = userLookup.accountLockedPropertyName
    String passwordExpiredPropertyName = userLookup.passwordExpiredPropertyName

    for (name in [enabled: enabledPropertyName,
                  accountExpired: accountExpiredPropertyName,
                  accountLocked: accountLockedPropertyName,
                  passwordExpired: passwordExpiredPropertyName]) {
        Integer value = params.int(name.key)
        if (value) {
            hql.append " AND u.${name.value}=:${name.key}"
            queryParams[name.key] = value == 1
        }
    }

    int totalCount = lookupUserClass().executeQuery("SELECT COUNT(DISTINCT u) $hql", queryParams)[0]

    Integer max = params.int('max')
    Integer offset = params.int('offset')

    String orderBy = ''
    if (params.sort) {
        orderBy = " ORDER BY u.$params.sort ${params.order ?: 'ASC'}"
    }

    def results = lookupUserClass().executeQuery(
            "SELECT DISTINCT u $hql $orderBy",
            queryParams, [max: max, offset: offset])
    def model = [results: results, totalCount: totalCount, searched: true]

    // add query params to model for paging
    for (name in ['username', 'enabled', 'accountExpired', 'accountLocked',
                  'passwordExpired', 'sort', 'order']) {
        model[name] = params[name]
    }

    render view: 'search', model: model
}

EDIT....

I believe it may have something to do with the code below:

def results = lookupUserClass().executeQuery(
            "SELECT DISTINCT u $hql $orderBy",
            queryParams, [max: max, offset: offset])

I think I just need to alter this statement so that it looks for the list of users where the currently logged in users "Area" is equal to the same area as the users. Can anyone please help me with this??

EDIT 2.....

I have now looked into this and have been able to obtain the users Area and now alls I need to do is to modify the query to the database to look for the users that have the same Area as the admin searching. I have tried the following with no luck, can someone please help me with this as I know this must be simple just cant seem to get there :-S

        def user = springSecurityService.currentUser
        def userArea = user.area

        def hql = new StringBuilder('FROM ').append(lookupUserClassName()).append(' u WHERE 1=1 AND u.area = userArea')

EDIT 3.......

Thanks so much half of my problem is solved lol, now just the Ajax piece:

I have tried the below code in order to modify the search for the Ajax function to only return results where the Area of the user is the same as the currently logged in user:

String username = params.term
            String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
            def user = springSecurityService.currentUser

            setIfMissing 'max', 10, 100

            def results = lookupUserClass().executeQuery(
                    "SELECT DISTINCT u.$usernameFieldName " +
                    "FROM ${lookupUserClassName()} u " +
                    "WHERE LOWER(u.$usernameFieldName) LIKE :name AND LOWER(u.area) = :area " +
                    "ORDER BY u.$usernameFieldName",
                    [name: "${username.toLowerCase()}%"],
                    [area: "user.area"],
                    [max: params.max])

Also tried changing the param as below:

[area: user.area]

The controller is building an HQL query, so you can't just say " WHERE u.area = userArea ", you'll need to use a named parameter and put the value in the queryParams map

    def user = springSecurityService.currentUser

    def hql = new StringBuilder('FROM ').append(lookupUserClassName()).append(
        ' u WHERE u.area = :userArea ')
    def queryParams = [userArea:user.area]

For the second part of the problem (the Ajax bit), I doubt you need the LOWER conversion, and also you need to put all your query parameters into one map (the second map parameter is just for the pagination settings):

def results = lookupUserClass().executeQuery(
   "SELECT DISTINCT u.$usernameFieldName " +
   "FROM ${lookupUserClassName()} u " +
   "WHERE LOWER(u.$usernameFieldName) LIKE :name AND u.area = :area " +
   "ORDER BY u.$usernameFieldName",
   [name: "${username.toLowerCase()}%", area:user.area],
   [max: params.max])

If you really do want the area check to be case-insensitive then leave it as LOWER(u.area) = :area but then you also need to convert the value you are testing against to lower case:

   [name: "${username.toLowerCase()}%", area:user.area.toLowerCase()],

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM