Grails定制安全评估程序

mnd*_*mnd 5 grails spring-security

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

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

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

#1我已经创建了一个自定义注解和使用过滤器来读取注释和检查访问,虽然这似乎更脆,只会给我控制器动作保护我,这将是很好也确保其他服务好.

我发现了一些信息,但没有完整.

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

这是关于使用SpEL的,但我希望在方法运行之前进行检查,以确保不会发生任何未经授权的影响.

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

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

mic*_*cha 10

你应该能够用弹簧安全和grails做到这一点,没有太多麻烦.

我过去使用以下两种方法来完成类似的任务.两者都需要弹簧安全ACL插件,它提供@PreAuthorize@PostAuthorize注释.

自定义PermissionEvaluator

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

@PreAuthorize("hasPermission(#myObject, 'update')")
public void updateSomething(myObject) {
  ..
}
Run Code Online (Sandbox Code Playgroud)

hasPermission()呼叫路由到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
    }
}
Run Code Online (Sandbox Code Playgroud)

要注册您,PermissionEvaluator您必须覆盖名为的bean expressionHandler.您可以通过添加以下行来执行此操作conf/spring/resources.groovy:

beans = {

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

    myPermissionEvaluator(MyPermissionEvaluator)

}
Run Code Online (Sandbox Code Playgroud)

resources.groovy你可以在内部定义bean,就像applicationContext.xml使用spring时一样.上面的行创建了一个MyPermissionEvaluator带有bean名称的bean类型myPermissionEvaluator.Spring证券expressionHandlerbean被类型的bean覆盖MyExpressionHandler.其他依赖项是从spring security ACL插件的配置文件中复制的.

服务调用安全注释

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

@PreAuthorize("@securityService.canAccess(#myObject)")
public void doSomething(myObject) {
  ..
}
Run Code Online (Sandbox Code Playgroud)

这将调用canAccessbean命名securityService的方法,并将方法参数传递给它.

要使用这个方法,你必须注册一个BeanResolverEvaluationContext.为此,您必须覆盖由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;
    }    
}
Run Code Online (Sandbox Code Playgroud)

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

class GrailsBeanResolver implements BeanResolver {

    GrailsApplication grailsApplication

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

}
Run Code Online (Sandbox Code Playgroud)

最后将豆子添加到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')
}
Run Code Online (Sandbox Code Playgroud)

更新(2013-10-22):最近我写了一篇关于这个的博客文章,提供了一些额外的信息.