Использование статических переменных в аннотациях 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'

есть ли способ получить доступ к статическим переменным с предварительного блокирования средств на аннотации?

4 ответов


попробуйте следующее, которое использует язык выражений Spring для оценки типа:

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

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

документация


чтобы можно было писать выражения без имен пакетов:

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

теперь создать свою.образец.Роли.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')")

принятый ответ от Кевина Бауэрсокса работает, но мне не понравилось иметь T(полностью.квалифицированный.path), поэтому я продолжал искать. Я начал с создания пользовательского метода безопасности, используя ответ от Джеймса Уоткинса здесь:

как создать пользовательские методы для использования в аннотациях языка выражений spring security

однако вместо строки я использовал свои перечисления.Класс разрешений в качестве типа параметра:

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

        ...do some work here...

        return true;
    }
}

Теперь аккуратная часть что когда я вызываю hasPermission из аннотации, мне не нужно вводить весь путь, но я должен заключить его в одинарные кавычки:

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

поскольку метод hasPermission ожидает перечисление, он автоматически найдет значение перечисления с этим именем. Если он не найдет его, вы получите исключение:

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

вы можете переименовать hasPermission в hasRole, в этом случае единственный компромисс заключается в том, что вы торгуете T(полностью.квалифицированный.путь) @mySecurityService и дополнительные одинарные кавычки.

не уверен, что это лучше, но это так. Поскольку ничто из этого не будет проверять значения во время компиляции, мой следующий шаг-сделать процессор аннотаций.

Я также должен отдать должное krosenvold за указание, что spring может автоматически преобразовываться в перечисление: https://stackoverflow.com/a/516899/618881


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

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

если ваше перечисление другого класса объявлено как public static, вам нужно использовать $ sign:

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

name() для предотвращения будущих проблем, если toString() будет переопределено позднее