2013-07-03 3 views
10

я использую аннотацию предварительного блокирования средств на Спринг следующим образом:Использования статических переменных в 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 Expression Language для оценки типа:

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

Обязательно укажите полное имя класса.

Documentation

+0

Прекрасно работает, спасибо! – RobEarl

+0

@RobEarl Awesome Glad Я мог бы помочь. Я тоже кое-что узнал. –

+0

Работает, но это все еще интерпретированная строка, поэтому она не будет «замечена» Eclipse, когда вы рефакторинг, например. имя, я думаю. – yglodt

3

Попробуйте что-то вроде этого:

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

Если OtherClass перечисления объявляются как публичные статические, то вам нужно использовать знак $:

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

name() для предотвращения Футера проблемы, если toString() будет переоцениваться позже

4

Принятый ответ от Кевина Боуэрсокса работает, но мне не нравилось иметь материал T (full.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)") 

делает его более читаемым IMHO. Также теперь набираются роли. Написать:

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

и вы получите запуска ошибки, которые не были бы там, если бы Вы писали:

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

Хорошее решение. Ошибки при запуске были бы хороши, но я не думаю, что вы можете добиться этого, как это. Оценка все еще происходит во время выполнения. Не нашли лучшего решения, но жесткого ... – chris