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.Methods 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.