The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section. Indeed we will only discuss the differences in this section.
The AspectJ interceptor is named
AspectJSecurityInterceptor
. Unlike the AOP Alliance
security interceptor, which relies on the Spring application context
to weave in the security interceptor via proxying, the
AspectJSecurityInterceptor
is weaved in via the
AspectJ compiler. It would not be uncommon to use both types of
security interceptors in the same application, with
AspectJSecurityInterceptor
being used for domain
object instance security and the AOP Alliance
MethodSecurityInterceptor
being used for services
layer security.
Let's first consider how the
AspectJSecurityInterceptor
is configured in the
Spring application context:
<bean id="bankManagerSecurity" class="org.springframework.security.intercept.method.aspectj.AspectJSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="afterInvocationManager" ref="afterInvocationManager"/> <property name="objectDefinitionSource"> <value> org.springframework.security.context.BankManager.delete*=ROLE_SUPERVISOR org.springframework.security.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR </value> </property> </bean>
As you can see, aside from the class name, the
AspectJSecurityInterceptor
is exactly the same as
the AOP Alliance security interceptor. Indeed the two interceptors can
share the same objectDefinitionSource
, as the
ObjectDefinitionSource
works with
java.lang.reflect.Method
s rather than an AOP
library-specific class. Of course, your access decisions have access
to the relevant AOP library-specific invocation (ie
MethodInvocation
or JoinPoint
)
and as such can consider a range of addition criteria when making
access decisions (such as method arguments).
Next you'll need to define an AspectJ aspect
.
For example:
package org.springframework.security.samples.aspectj; import org.springframework.security.intercept.method.aspectj.AspectJSecurityInterceptor; import org.springframework.security.intercept.method.aspectj.AspectJCallback; import org.springframework.beans.factory.InitializingBean; public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { private AspectJSecurityInterceptor securityInterceptor; pointcut domainObjectInstanceExecution(): target(PersistableEntity) && execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect); Object around(): domainObjectInstanceExecution() { if (this.securityInterceptor == null) { return proceed(); } AspectJCallback callback = new AspectJCallback() { public Object proceedWithObject() { return proceed(); } }; return this.securityInterceptor.invoke(thisJoinPoint, callback); } public AspectJSecurityInterceptor getSecurityInterceptor() { return securityInterceptor; } public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) { this.securityInterceptor = securityInterceptor; } public void afterPropertiesSet() throws Exception { if (this.securityInterceptor == null) throw new IllegalArgumentException("securityInterceptor required"); } }
In the above example, the security interceptor will be applied
to every instance of PersistableEntity
, which is an
abstract class not shown (you can use any other class or
pointcut
expression you like). For those curious,
AspectJCallback
is needed because the
proceed();
statement has special meaning only
within an around()
body. The
AspectJSecurityInterceptor
calls this anonymous
AspectJCallback
class when it wants the target
object to continue.
You will need to configure Spring to load the aspect and wire it
with the AspectJSecurityInterceptor
. A bean
declaration which achieves this is shown below:
<bean id="domainObjectInstanceSecurityAspect" class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect" factory-method="aspectOf"> <property name="securityInterceptor" ref="aspectJSecurityInterceptor"/> </bean>
That's it! Now you can create your beans from anywhere within
your application, using whatever means you think fit (eg new
Person();
) and they will have the security interceptor
applied.