5

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

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

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

对于#1,我创建了一个自定义注释,并使用过滤器来读取注释并检查访问,尽管这似乎更脆弱,只会为我提供对控制器操作的保护,而且保护其他服务也很好出色地。

我发现了一些这些信息,但没有完整的。

THIS讨论自定义 ACL,但仅针对新权限,而不是控制逻辑

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

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

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

4

1 回答 1

10

您应该可以使用 spring security 和 grails 轻松做到这一点。

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

自定义权限评估器

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

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

hasPermission()调用由 spring security 路由到a 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. 您可以通过在 中添加以下行来执行此操作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定义bean,就像你在applicationContext.xml使用spring时所做的那样。上面几行创建了一个类型MyPermissionEvaluator为 bean name 的 bean myPermissionEvaluator。Spring 证券expressionHandlerbean 被一个 bean 类型覆盖MyExpressionHandler。其他依赖从 spring security ACL 插件的配置文件中复制。

安全注释中的服务调用

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

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

这将调用canAccess命名 beansecurityService的方法并将方法参数传递给它。

要使用这种方法,您必须在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)
    }

}

最后将豆子添加到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):最近我写了一篇关于这个的博客文章,它提供了一些额外的信息。

于 2013-07-22T18:34:11.863 回答