Как создать пользовательские методы для использования в выражениях выражения выражения весны безопасности
Я хотел бы создать class, который добавляет пользовательские методы для использования в языке выражения весны безопасности для авторизации на основе метода через annotations.
Например, я хотел бы создать собственный метод, например customMethodReturningBoolean, который будет использоваться так:
@PreAuthorize("customMethodReturningBoolean()") public void myMethodToSecure() { // whatever }
Мой вопрос таков. Если это возможно, какой class должен быть подclassом для создания моих настраиваемых методов, как бы я решил настроить его в конфигурационных файлах весны xml и пришел ли кто-нибудь, чтобы я привел пример пользовательского метода, используемого таким образом?
- Как использовать OAuth2RestTemplate?
- Как получить доступ к параметрам задания из ItemReader, в Spring Batch?
- пружинный сердечник 3.2.9 + java 8
- Как исправить роль в Spring Security?
- Как получить активные пользовательские UserDetails
- Как управлять исключениями, сброшенными фильтрами весной?
- Spring Security: несколько HTTP-конфигураций не работают
- Понимание использования Spring @Autowired
- Поддержка / объяснение иерархии файлов Spring XML.
- Почему Spring MVC отвечает 404 и сообщает «Нет сопоставления для HTTP-запроса с URI в DispatcherServlet»?
- Фильтр дважды вызывается при регистрации как Spring bean
- Только использование @JsonIgnore во время сериализации, но не десериализация
- Почему RestTemplate не связывает ответное представление с PagedResources?
Вам нужно подclassифицировать два classа.
Сначала установите новый обработчик выражения метода
myMethodSecurityExpressionHandler
будет подclassом DefaultMethodSecurityExpressionHandler
который переопределяет createEvaluationContext()
, устанавливая подclass MethodSecurityExpressionRoot
в MethodSecurityEvaluationContext
.
Например:
@Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer); MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth); root.setTrustResolver(trustResolver); root.setPermissionEvaluator(permissionEvaluator); root.setRoleHierarchy(roleHierarchy); ctx.setRootObject(root); return ctx; }
Ни один из вышеупомянутых методов не будет работать больше. Похоже, что Spring прошла долгий путь, чтобы пользователи не переопределили SecurityExpressionRoot.
EDIT 11/19/14 Настройка Spring для использования аннотаций безопасности:
...
Создайте bean-компонент следующим образом:
@Component("mySecurityService") public class MySecurityService { public boolean hasPermission(String key) { return true; } }
Затем сделайте что-то подобное в jsp:
Или аннотируйте метод:
@PreAuthorize("@mySecurityService.hasPermission('special')") public void doSpecialStuff() { ... }
И помните: если вы используете Spring, и вам приходится решать проблему, расширяя classы, переопределяя методы, реализуя интерфейсы и т. Д. … тогда вы, вероятно, что-то делаете неправильно. Это все annotations и xml, поэтому мы очень любим Spring, а не (старые версии) EJB.
Кроме того, вы можете использовать Spring Expression Language в своих @PreAuthorize
для доступа к текущей аутентификации, а также аргументам метода.
Например:
@Component("mySecurityService") public class MySecurityService { public boolean hasPermission(Authentication authentication, String foo) { ... } }
Затем обновите свой @PreAuthorize
чтобы он соответствовал новой сигнатуре метода:
@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)") public void doSpecialStuff(String foo) { ... }
Спасибо ericacm , но это не работает по нескольким причинам:
- Свойства DefaultMethodSecurityExpressionHandler являются частными (нежелательные видимости)
- По крайней мере, в моем Eclipse я не могу разрешить объект MethodSecurityEvaluationContext
Различия в том, что мы вызываем существующий метод createEvaluationContext, а затем добавляем наш пользовательский корневой объект. Наконец, я просто вернул тип объекта StandardEvaluationContext, поскольку метод MethodSecurityEvaluationContext не будет разрешен в компиляторе (они оба из одного и того же интерфейса). Это код, который я сейчас имею в производстве.
Сделать методSecurityExpressionHandler использовать наш собственный корень:
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { // parent constructor public CustomMethodSecurityExpressionHandler() { super(); } /** * Custom override to use {@link CustomSecurityExpressionRoot} * * Uses a {@link MethodSecurityEvaluationContext} as the EvaluationContext implementation and * configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object. */ @Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { // due to private methods, call original method, then override it's root with ours StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi); ctx.setRootObject( new CustomSecurityExpressionRoot(auth) ); return ctx; } }
Это заменяет корень по умолчанию, расширяя SecurityExpressionRoot . Здесь я переименовал hasRole в hasEntitlement:
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot { // parent constructor public CustomSecurityExpressionRoot(Authentication a) { super(a); } /** * Pass through to hasRole preserving Entitlement method naming convention * @param expression * @return boolean */ public boolean hasEntitlement(String expression) { return hasRole(expression); } }
Наконец обновите securityContext.xml (и убедитесь, что он ссылается на ваш applcationContext.xml):
Примечание: аннотация @Secured не принимает это переопределение при прохождении через другой обработчик проверки. Итак, в приведенном выше xml я отключил их, чтобы предотвратить путаницу.