Grails 自定义安全评估器

Posted

技术标签:

【中文标题】Grails 自定义安全评估器【英文标题】:Grails custom security evaluator 【发布时间】:2013-07-21 07:41:40 【问题描述】:

我正在开发一个必须执行对象级别安全检查的应用程序,并且这些检查将由服务进行,因为它需要对单独的应用程序进行 REST 调用。因此,我无法使用 Spring Security 角色或 ACL,因为这些信息都不会本地存储在应用程序中。我正在尝试找到一种优雅的方式来处理这个问题,这里有两个我能想到的选择:

1) 创建一个将检查权限的自定义注解

2) 扩展 Spring 安全注释权限检查(可能使用 Permission Evaluator?),让我编写检查访问的逻辑

对于#1,我创建了一个自定义注释,并使用过滤器来读取注释并检查访问权限,尽管这似乎更脆弱,只会为我提供对控制器操作的保护,而且还可以确保安全其他服务也是如此。

我找到了这些信息的一小部分,但没有完整的。

THIS 谈到自定义 ACL 但只是为了新的权限,而不是控制逻辑

THIS 谈到使用 SpEL,但我想在方法运行之前进行检查,以确保不会发生未经授权的影响。

THIS 似乎最接近我想要做的,但特定于 Spring Security 而不是 Grails - 我最大的挑战是将 applicationContext.xml 中的信息转换为 resources.groovy

提前感谢您提出的任何建议或意见!

【问题讨论】:

不确定这是不是最好的方法,但你所说的安全性我已经通过过滤器完成了。 感谢@JamesKleeh 的回复,您是否遇到了仅过滤控制器操作的问题? 不,我没有遇到任何无法以这种方式完成的事情。还有什么可以保障的?静态内容? 提供更清晰的图片。我创建了一个服务方法来确定权限。然后,如果出于某种原因该逻辑必须在视图中,我创建一个执行该服务方法的标记库。然后我也在我的过滤器中执行相同的服务方法。这样一来,所有事情的逻辑都集中在一个地方。 【参考方案1】:

您应该能够使用 spring security 和 grails 轻松完成此操作。

我过去曾使用以下两种方式来完成类似的任务。两者都需要提供@PreAuthorize@PostAuthorize 注释的spring security ACL 插件。

自定义权限评估器

您可以在安全注释中使用hasPermission() 方法并创建自定义PermissionEvaluator。在代码中,这看起来像这样:

@PreAuthorize("hasPermission(#myObject, 'update')")
public void updateSomething(myObject) 
  ..

hasPermission() 调用由 spring security 路由到PermissionEvaluator。要编写自己的实现,您必须实现 PermissionEvaluator 接口:

class MyPermissionEvaluator implements PermissionEvaluator 

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) 
        // your custom logic..
    

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) 
        // your custom logic
    

要注册您的PermissionEvaluator,您必须覆盖名为expressionHandler 的bean。为此,您可以在 conf/spring/resources.groovy 中添加以下行:

beans = 

    expressionHandler(MyExpressionHandler) 
        parameterNameDiscoverer = ref('parameterNameDiscoverer')
        permissionEvaluator = ref('myPermissionEvaluator') // your PermissionEvaluator
        roleHierarchy = ref('roleHierarchy')
        trustResolver = ref('authenticationTrustResolver')
    

    myPermissionEvaluator(MyPermissionEvaluator)


resources.groovy 中,您可以像在使用spring 时在applicationContext.xml 中那样定义bean。以上行创建了一个类型为MyPermissionEvaluator 的bean,bean 名称为myPermissionEvaluator。 Spring 证券 expressionHandler bean 被 MyExpressionHandler 类型的 bean 覆盖。其他依赖是从spring security ACL插件的配置文件中拷贝过来的。

安全注释中的服务调用

如果hasPermission() 方法的设计不能满足您的所有要求,您可以改用简单的服务调用。 @PostAuthorize@PreAuthorize 注释使用 SPEL 来评估表达式。在 SPEL 中,您可以使用 @ 符号来访问 bean。例如:

@PreAuthorize("@securityService.canAccess(#myObject)")
public void doSomething(myObject) 
  ..

这会调用名为securityService 的bean 的canAccess 方法并将方法参数传递给它。

要使用这种方法,您必须在EvaluationContext 上注册BeanResolver。为此,您必须覆盖由 spring security ACL 插件配置的DefaultMethodSecurityExpressionHandler。

这可能如下所示:

class MyExpressionHandler extends DefaultMethodSecurityExpressionHandler 

    BeanResolver beanResolver

    @Override
    public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) 
        StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi)
        ctx.setBeanResolver(beanResolver) // set BeanResolver here
        return ctx;
        

BeanResolver 是一个简单的接口,可以将 bean 名称解析为 bean 实例:

class GrailsBeanResolver implements BeanResolver 

    GrailsApplication grailsApplication

    @Override
    public Object resolve(EvaluationContext evaluationContext, String beanName) throws AccessException 
        return grailsApplication.mainContext.getBean(beanName)
    


最后将 bean 添加到 resources.groovy:

expressionHandler(MyExpressionHandler) 
    parameterNameDiscoverer = ref('parameterNameDiscoverer')
    permissionEvaluator = ref('permissionEvaluator')
    roleHierarchy = ref('roleHierarchy')
    trustResolver = ref('authenticationTrustResolver')
    beanResolver = ref('beanResolver') // this is your BeanResolver


// This is the service called within security expressions
// If you place your service in the grails service folder you can skip this line
securityService(MySecurityService) 

// this is your BeanResolver
beanResolver(GrailsBeanResolver) 
    grailsApplication   = ref('grailsApplication')

更新 (2013-10-22):最近我写了一个blog post 正是关于这个,它提供了一些额外的信息。

【讨论】:

这很棒,非常完整,谢谢@micha!只是为了评论(以防其他人遇到此问题),这些调用适用于 service 方法,而不适用于 controller 方法,因此请小心放置注释。

以上是关于Grails 自定义安全评估器的主要内容,如果未能解决你的问题,请参考以下文章

来自另一个域类的属性的 Grails 自定义验证器

保密安全风险自评估单机版检查工具V1.0

信息安全工程师笔记-网络安全风险评估技术原理与应用

国内首家!阿里云专有云通过商用密码应用安全性评估

数据安全与资产管理·可用性评估

汽车功能安全 - 危险分析和风险评估