2013-07-22 66 views
3

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

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

2)扩展Spring的安全注解权限检查(可能与权限评估?),让我写检查访问的逻辑

对于#1我创建了一个自定义注释,并使用过滤器来读取注释和检查访问,虽然这似乎更脆弱,只会为控制器操作提供保护,而且还能够保证其他服务的安全。

我发现这些信息有点片断,但没有完成。

THIS有关自定义ACL,但只有一个新的许可,而不是控制逻辑

THIS会谈有关使用规划环境地政司,但我想有一个检查方法运行之前,确保没有任何影响需要谈判那将是未经授权的地方。

THIS似乎是最接近我想要做的,但具体到春季安全,而不是Grails的 - 我的最大的挑战是转换信息的applicationContext.xml到resources.groovy

预先感谢任何建议或建议,你可能有!

+0

不知道这是最好的方式,但你谈论的安全性我通过过滤器完成。 –

+0

感谢@JamesKleeh的回应,是否遇到任何问题只能过滤控制器操作? – mnd

+0

不,我没有遇到任何不能这样做的事情。还有什么可以保证的?静态内容? –

回答

8

你应该可以在没有太多麻烦的情况下用spring security和grails来做到这一点。

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

定制PermissionEvaluator

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

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

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 
    } 
} 

要注册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您可以定义豆类,就像您在使用applicationContext.xml春天的时候做。以上几行创建了一个类型为MyPermissionEvaluator的豆,豆名为myPermissionEvaluator。 Spring证券expressionHandler bean被一个类型为MyExpressionHandler的bean所覆盖。其他依赖项是从spring security ACL插件的配置文件中复制的。

服务中的安全注解调用

如果的hasPermission()方法的设计并不achive你的要求,你可以使用简单的服务调用来代替。 @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) 
    } 

} 

最后豆子添加到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') 
} 

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

+0

这很棒,很完整,谢谢@micha!只是为了评论(以防其他人遇到此问题),这些调用在* service *方法上工作,而不是在* controller *方法上,所以只要注意放置注释的位置即可。 – mnd