2010-05-17 3 views
27

У меня есть класс обслуживания, реализованный в Java 6/Spring 3, который требует аннотации для ограничения доступа по ролям.Точка привязки Spring AOP, которая соответствует аннотации по интерфейсу

Я определил аннотацию под названием RequiredPermission, который имеет в качестве атрибута его значение одного или нескольких значений из перечислений под названием OperationType:

public @interface RequiredPermission { 

/** 
* One or more {@link OperationType}s that map to the permissions required 
* to execute this method. 
* 
* @return 
*/ 
OperationType[] value();} 

public enum OperationType { 
     TYPE1, 
     TYPE2; 
} 

package com.mycompany.myservice; 
public interface MyService{ 
    @RequiredPermission(OperationType.TYPE1) 
    void myMethod(MyParameterObject obj); 
} 

package com.mycompany.myserviceimpl; 
public class MyServiceImpl implements MyService{ 
    public myMethod(MyParameterObject obj){ 
     // do stuff here 
    } 
} 

У меня также есть следующее определение аспект:

/** 
* Security advice around methods that are annotated with 
* {@link RequiredPermission}. 
* 
* @param pjp 
* @param param 
* @param requiredPermission 
* @return 
* @throws Throwable 
*/ 
@Around(value = "execution(public *" 
     + " com.mycompany.myserviceimpl.*(..))" 
     + " && args(param)" + // parameter object 
     " && @annotation(requiredPermission)" // permission annotation 

, argNames = "param,requiredPermission") 
public Object processRequest(final ProceedingJoinPoint pjp, 
     final MyParameterObject param, 
     final RequiredPermission requiredPermission) throws Throwable { 
    if(userService.userHasRoles(param.getUsername(),requiredPermission.values()){ 
     return pjp.proceed(); 
    }else{ 
     throw new SorryButYouAreNotAllowedToDoThatException(
      param.getUsername(),requiredPermission.value()); 
    } 
} 

объект параметра содержит имя пользователя, и я хочу найти требуемую роль для пользователя, прежде чем разрешить доступ к этому методу.

Когда я помещаю аннотацию на метод в MyServiceImpl, все работает отлично, привязка pointcut и нос. Но я считаю, что аннотация является частью контракта на обслуживание и должна быть опубликована с помощью интерфейса в отдельный пакет API. И, очевидно, я бы не хотел ставить аннотацию на определение и реализацию сервиса (DRY).

Я знаю, что есть случаи в Spring AOP, где аспекты инициируются аннотациями одним способом интерфейса (например, Transactional). Здесь есть специальный синтаксис или это просто невозможно из коробки.

PS: Я не разместил свою конфигурацию пружины, поскольку она работает нормально. И нет, это не мои первоначальные классы и имена методов.

PPS: На самом деле, вот соответствующая часть моей весенней конфигурации:

<aop:aspectj-autoproxy proxy-target-class="false" /> 

<bean class="com.mycompany.aspect.MyAspect"> 
    <property name="userService" ref="userService" /> 
</bean> 
+0

Итак, если я правильно понимаю, самое лучшее решение, которое вы нашли для вашего первоначального вопроса (то есть, имеющие пометку в интерфейс, а не в реализации) заключается в том, чтобы сопоставить весь пакет интерфейсов поставщика услуг, а затем зайти в ProceedingJoinPoint, чтобы узнать аннотации метода в интерфейсе? Возможно ли это? Это отличный поток, и вы не хотите начинать новый с тем же вопросом! Благодаря!! – espinchi

+0

@espinchi на самом деле я был настолько расстроен, что я скопировал все аннотации из интерфейса к классу внедрения и принудительно применил это с помощью жесткого модульного теста, который проверял все методы как на интерфейсе, так и на классе реализации для идентичных аннотаций. Я не знаю точно, АОП. Я бы сказал, что это не работает надежно, ведь –

ответ

28

Если я понимаю, что вы исправить, вы хотите Pointcut, который находит все методы в классах, которые распространяются MyService и аннотированные и с предпочтительные аргументы.

Я предлагаю вам заменить:

execution(public * com.mycompany.myserviceimpl.*(..)) 

с:

execution(public * com.mycompany.myservice.MyService+.*(..)) 

Знак плюс используется, если вы хотите, чтобы соответствовать joinpoint класс MyService или класс, который расширяет его.

Надеюсь, это поможет!

+0

Существует небольшая опечатка. это фактически: исполнение (публичный * com.mycompany.myservice.MyService +. * (..)) Но он работает как шарм. Большое спасибо!!! –

+0

Это хорошо! Я исправлю свой ответ, чтобы включить подстановочный знак для всех методов. – Espen

+1

Я понял намного позже, что это не совсем правильно (хотя, вероятно, это лучший выбор). Я хотел, чтобы аннотация была в методе сервисного интерфейса, но это работает только в том случае, если аннотация находится в методе реализации. И так как мне также нужно это поведение: http://stackoverflow.com/questions/3100228/spring-aop-pointcut-expression-to-access-method-return-type, я должен держать pointcut минимальным и проверять объект continueinginpointpoint себя. –

4

Эспен, ваш код работает только для одного класса:.

execution(public * com.mycompany.myservice.MyService+.*(..)) 

но что, если я хочу это поведение для всех услуг в * com.mycompany.services ** пакет?

+1

это хорошо работает: исполнение (публичный * com.mycompany.myservice. * +. * (..)) –

0

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

execution(public * com.mycompany.myservice.MyService+.*(..)) 

Тогда совет вызывается. Однако, если я добавлю это:

Тогда совет не вызывается. Интерфейс MyService содержит аннотацию @Logged по одному из своих методов и даже по объявлению типа.

+1

попробуйте использовать && @annotation (myparam) и пусть у вас есть параметр с именем myparam типа Записан (даже если вы не нужно) –

+1

Это тоже не работает. Вот мой совет: ". Исполнение (публичные * abcdservices * + * (..)) &&" @Around (значение = \t \t \t + "мишень (боб) &&" \t \t \t + «@annotation (logged) ", argNames =" bean, logged ") – user348237

+1

yup, это верно. Аннотирование должно выполняться по методу реализации, а не по методу интерфейса службы. –

0

Вы должны добавить аннотацию @Inherited в свою аннотацию @RequiredPermission.

http://download.oracle.com/javase/6/docs/api/java/lang/annotation/Inherited.html

+6

'@ Inherited' работает только на уровне класса, а не на уровне метода:« Обратите внимание, что этот тип мета-аннотации не действует, если аннотированный тип используется для комментирования чего-либо другого, кроме класса. Обратите также внимание, что эта мета-аннотация вызывает аннотации наследования от суперклассов, аннотации на реализованных интерфейсах не влияют ». –

+0

Не знал, что ... спасибо! –

Смежные вопросы