您应该可以使用 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 证券expressionHandler
bean 被一个 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):最近我写了一篇关于这个的博客文章,它提供了一些额外的信息。