2013-07-03 95 views
10

我使用Spring的預授權註解如下靜態變量:使用Spring註解

@PreAuthorize("hasRole('role')"); 

不過,我已經定義爲另一個類的靜態字符串「角色」。如果我嘗試使用這個值:

@PreAuthorize("hasRole(OtherClass.ROLE)"); 

我得到一個錯誤:

org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 14): Field or property 'OtherClass' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot' 

有沒有像這樣訪問靜態變量與預授權註釋的方法嗎?

回答

16

嘗試它使用Spring表達式語言來評價類型如下:

@PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)"); 

確保指定的完全限定類名。

Documentation

+0

偉大的作品,謝謝! – RobEarl

+0

@RobEarl真棒很高興我能幫到你。我也學到了一些東西。 –

+0

Works,但它仍然是一個解釋的字符串,所以當您重構例如Eclipse時,它不會被Eclipse「看到」。我猜的名字。 – yglodt

3

嘗試是這樣的:如果你的OtherClass枚舉被聲明爲公共靜態

@PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())"); 

,那麼你需要使用$符號:

@PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())"); 

name()防止futer問題如果toString()將在以後被覆蓋

4

凱文鮑爾索克斯接受的答案的作品,但我不喜歡有T(fully.qualified.path)的東西,所以我一直在尋找。我開始通過創建使用從詹姆斯·沃特金斯這裏的答案自定義的安全方法:

How to create custom methods for use in spring security expression language annotations

然而,而不是一個字符串,我用我的enums.Permissions類作爲參數類型:

@Component 
public class MySecurityService { 
    public boolean hasPermission(enums.Permissions permission) { 

     ...do some work here... 

     return true; 
    } 
} 

現在整齊的部分是,當我打電話從註釋調用hasPermission,我沒有有鍵入完整的路徑,但我必須把它們放在單引號:

@PreAuthorize("@mySecurityService.hasPermission('SOME_ROLE_NAME')") 

因爲hasPermission方法需要Enum,它將自動查找具有該名稱的Enum值。如果它沒有找到它,你會得到一個例外:

org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from java.lang.String to enums.Permissions 

可以重命名調用hasPermission到hasRole,在這種情況下唯一的代價就是你的交易T(fully.qualified.path) @mySecurityService和額外的單引號。

不知道它是否更好,但它是。由於無論如何都不會驗證編譯時的值,我的下一步是創建一個註釋處理器。

我也必須給予信貸krosenvold您指出彈簧能自動轉換爲一個枚舉: https://stackoverflow.com/a/516899/618881

6

爲了能夠寫出表達式,而不包名:

<sec:global-method-security> 
    <sec:expression-handler ref="methodSecurityExpressionHandler"/> 
</sec:global-method-security> 

<bean id="methodSecurityExpressionHandler" class="my.example.DefaultMethodSecurityExpressionHandler"/> 

然後擴展DefaultMethodSecurityExpressionHandler:

public class DefaultMethodSecurityExpressionHandler extends org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler { 

    @Override 
    public StandardEvaluationContext createEvaluationContextInternal(final Authentication auth, final MethodInvocation mi) { 
     StandardEvaluationContext standardEvaluationContext = super.createEvaluationContextInternal(auth, mi); 
     ((StandardTypeLocator) standardEvaluationContext.getTypeLocator()).registerImport("my.example"); 
     return standardEvaluationContext; 
    } 
} 

現在創建my.example.Roles.java:

public class Roles { 

    public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED"; 

    public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED"; 
} 

,並參考其不包名稱註釋:的

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)") 

代替:

@PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)") 

使它更具可讀性恕我直言。現在還鍵入角色。寫:

@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)") 

,你會得到一個不會在那裏,如果你寫的啓動錯誤:

@PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')") 
+0

好的解決方案。有啓動錯誤會很好,但我不認爲你可以實現這樣的。評估仍然在運行時發生。還沒有找到更好的解決方案,但很難... – chris