9

Spring Security非常适合进行基于角色的授权,但在基于规则的授权方面似乎有所不足。当然,有一些方法可以通过 SpEL 来实现,但走这条路似乎会将您的授权逻辑锁定在注释中,而将逻辑提取到服务中会更好,以便多个地方可以使用相同的逻辑。

似乎有一些 方法 可以添加 自己的 SpEL 表达式,但注意特别清楚,甚至那些对我来说有意义的方法似乎也达不到要求。我认为,鉴于Groovy 的灵活性,必须有某种方法不必将依赖项硬编码在一起,而是在运行时获取安全规则(或 SpEL 扩展)。

虽然并不理想,但即使像定义所有所需的新规则并注入 as mixins(即。SecurityExpressionRoot.mixin MyRule1)这样看似简单的事情也是一个好的开始,但这似乎不起作用。

有谁知道这样做的例子?如果没有,我自己怎么做呢?


一个(简化)示例:如果 4 个字段中有 3 个的值超过特定阈值,则用户只能对对象执行特定操作(即执行服务方法),但前提是对象小于 3 天:

class MyRule {

    boolean canTakeAction(Person person, MyThing myThing) {
        int numFieldsWithValues = 0
        if (myThing.field1 != null) { numFieldsWithValues++ }
        if (myThing.field2 != null) { numFieldsWithValues++ }
        if (myThing.field3 != null) { numFieldsWithValues++ }
        if (myThing.field4 != null) { numFieldsWithValues++ }

        return (numFieldsWithValues > 3) && (ageInDays(myThing) < 3)
    }

    int ageInDays(MyThing myThing) {
        ...
    }
}

这是更简单的规则之一。

4

3 回答 3

2

基于角色的授权是最简单但不太灵活的方式。与此形成对比的是 Spring 安全ACL 系统。ACL 让您可以精确定义可以在运行时对哪个对象执行什么操作。另一方面,这需要更复杂的设置。还有一个用于此的 grails 插件

使用带有 SpEL 表达式的注释的方式介于这两种选择之间。它们比简单的角色更灵活,比 ACL 更容易。如果您正在寻找有关 Grails 中方法安全性的介绍,那么我前段时间写的这篇博文可能会对您有所帮助。

于 2012-12-18T22:45:26.503 回答
1

您可以在提供动态配置功能的Requestmap中管理您的规则。

例如,首先在 config.groovy 中将安全类型定义为 requestmap:

grails.plugins.springsecurity.securityConfigType = "Requestmap"

然后你可能有类似于 User 和 Role 的 Requestmap 域类,像这样:

package com.app.auth
class Requestmap {

    String url
    String configAttribute

    static mapping = {
        cache true
    }

    static constraints = {
        url blank: false
        configAttribute blank: false
    }
}

现在,由于 User、Role 和 Reqestmap 都保存在数据库中,您可以通过某些控制器中的 CRUD 操作轻松更改您的规则,而无需重新部署或重新启动您的服务。像这样:

class RequestmapController {

def springSecurityService

...

def save = { 
    def requestmapInstance = new Requestmap(params) 
    if (!requestmapInstance.save(flush: true)) { 
        render view: 'create', model: [requestmapInstance: requestmapInstance] 
        return 
    }

    springSecurityService.clearCachedRequestmaps()     //This is important: to refresh the requestmap. Without it the rules remain unchanged.
    flash.message = "${message(code: 'default.created.message', args: [message(code: 'requestmap.label', default: 'Requestmap'), requestmapInstance.id])}" 
    redirect action: show, id: requestmapInstance.id 
    } 
}

在视图层中,您可以使用 spring 安全标签来管理您的菜单、按钮和其他需要授权的元素,例如:

<sec:access url="foo/bar">
    <li><g:link class="list" controller="foo" action="bar">Bar action</g:link></li>
</sec:access>

因此,视图也符合授权规则。

此外,还有一个分层角色功能可以用来减少请求映射中的混乱。

于 2012-12-19T04:15:54.187 回答
0

从您发布的示例中,GContracts可能是您正在寻找的。您只需要弄清楚在运行 GContract 闭包时如何访问 Principal ,但这可能就像将其作为参数传递给收缩方法一样简单。

于 2012-12-19T14:42:41.190 回答