2013-07-22 67 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