java - que - spring boot aop
Punto de corte Spring AOP que coincide con la anotaciĆ³n en la interfaz (5)
Tengo una clase de servicio implementada en Java 6 / Spring 3 que necesita una anotación para restringir el acceso por rol.
He definido una anotación llamada RequiredPermission que tiene como atributo de valor uno o más valores de una enumeración llamada 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
}
}
También tengo la siguiente definición de aspecto:
/**
* 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());
}
}
El objeto de parámetro contiene un nombre de usuario y quiero buscar el rol requerido para el usuario antes de permitir el acceso al método.
Cuando coloco la anotación en el método en MyServiceImpl, todo funciona bien, el pointcut coincide y el aspecto entra en acción. Sin embargo, creo que la anotación es parte del contrato de servicio y debe publicarse con la interfaz en un paquete API separado. . Y obviamente, no me gustaría poner la anotación tanto en la definición del servicio como en la implementación (DRY).
Sé que hay casos en Spring AOP donde los aspectos se desencadenan mediante las anotaciones de un método de interfaz (por ejemplo, Transactional). ¿Hay una sintaxis especial aquí o es simplemente imposible de usar?
PD: No he publicado mi configuración de primavera, ya que parece estar funcionando bien. Y no, esos no son mis nombres originales de clase o método.
PPS: en realidad, aquí está la parte relevante de mi configuración de primavera:
<aop:aspectj-autoproxy proxy-target-class="false" />
<bean class="com.mycompany.aspect.MyAspect">
<property name="userService" ref="userService" />
</bean>
Debe agregar la anotación @Hermitida a su anotación @RequiredPermission.
http://download.oracle.com/javase/6/docs/api/java/lang/annotation/Inherited.html
Espen, tu código funciona solo para una clase:
execution(public * com.mycompany.myservice.MyService+.*(..))
pero, ¿qué sucede si deseo este comportamiento para todos los servicios en el paquete * com.mycompany.services. **?
He tenido éxito con este enfoque:
http://nonrepeatable.blogspot.co.uk/2010/05/validating-service-method-parameters.html
Me encontré con el mismo problema, sin embargo, las sugerencias anteriores no ayudan. Si solo tengo esto como punto de corte:
execution(public * com.mycompany.myservice.MyService+.*(..))
Entonces el consejo es invocado. Sin embargo, si agrego esto:
&& @annotation(x.y.z.Logged)
Entonces el consejo no es invocado. La interfaz MyService contiene una anotación @Logged en uno de sus métodos e incluso en su declaración de tipo.
Si entiendo que es correcto, quiere un corte de punto que encuentre todos los métodos en las clases que extienda MyService y esté anotado y con los argumentos preferidos.
Propongo que reemplaces:
execution(public * com.mycompany.myserviceimpl.*(..))
con:
execution(public * com.mycompany.myservice.MyService+.*(..))
El signo más se utiliza si desea que un punto de unión coincida con la clase MyService o una clase que lo amplíe.
¡Espero que ayude!