aop:config在shiro許可權註解中發揮的作用
問題
spring-shiro.xml中通常會加aop配置,以使shiro認證註解(@RequiresPermissions、@RequiresRoles、@RequiresUser、@RequiresGuest
)work。
通常配置如下
<aop:config />
<!--許可權註解的advisor -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
但是我有一個問題!<aop:config/>
裡沒有配置通知,也沒有配置切點,shiro的認證註解怎麼就work了呢?
我們注意到有個AuthorizationAttributeSourceAdvisor
配置,它是一個通知器。
類層次圖
觀察類層次結構圖,可以看到它實現了pointcut
,我們知道pointcut就是切點,它會判斷匹配哪些類,並返回方法匹配
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
pointcut中一共兩個介面方法,一個是getClassFilter
,一個是getMethodMatcher
。
getClassFilter匹配所有類
AuthorizationAttributeSourceAdvisor
的父類StaticMethodMatcherPointcut
中,實現了getClassFilter
、getMethodMatcher
方法。
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
private ClassFilter classFilter = ClassFilter.TRUE;
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.classFilter = classFilter;
}
@Override
public ClassFilter getClassFilter() {
return this.classFilter;
}
@Override
public final MethodMatcher getMethodMatcher() {
return this;
}
}
繼續追蹤,類屬性classFilter是ClassFilter.TRUE
,最終跟蹤到TrueClassFilter
,matches方法始終返回true,所以AuthorizationAttributeSourceAdvisor
會匹配所有類!
class TrueClassFilter implements ClassFilter, Serializable {
public static final TrueClassFilter INSTANCE = new TrueClassFilter();
/**
* Enforce Singleton pattern.
*/
private TrueClassFilter() {
}
@Override
public boolean matches(Class<?> clazz) {
return true;
}
}
getMethodMatcher匹配所有加了認證註解的方法
再看方法匹配,注意StaticMethodMatcherPointcut
的getMethodMatcher
返回的是this,因為AuthorizationAttributeSourceAdvisor
實現了MethodMatcher
介面,所以返回的this就是AuthorizationAttributeSourceAdvisor
本身。MethodMatcher
matches方法用來判斷方法匹配。
可以看到它會匹配所有加了認證註解的方法。
AuthorizationAttributeSourceAdvisor.java
private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
new Class[] {
RequiresPermissions.class, RequiresRoles.class,
RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
};
public boolean matches(Method method, Class targetClass) {
Method m = method;
if ( isAuthzAnnotationPresent(m) ) {
return true;
}
//The 'method' parameter could be from an interface that doesn't have the annotation.
//Check to see if the implementation has it.
if ( targetClass != null) {
try {
m = targetClass.getMethod(m.getName(), m.getParameterTypes());
if ( isAuthzAnnotationPresent(m) ) {
return true;
}
} catch (NoSuchMethodException ignored) {
//default return value is false. If we can't find the method, then obviously
//there is no annotation, so just use the default return value.
}
}
return false;
}
private boolean isAuthzAnnotationPresent(Method method) {
for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
Annotation a = AnnotationUtils.findAnnotation(method, annClass);
if ( a != null ) {
return true;
}
}
return false;
}
aop:config
至今,我們有了一個完整的切面認識AuthorizationAttributeSourceAdvisor
- 匹配所有類
- 匹配所有加認證註解的方法
我們知道,<aop:config/>
會掃描配置檔案中的所有advisor,併為其建立代理。正是有個<aop:config/>
加上AuthorizationAttributeSourceAdvisor
,所以認證註解才會work
總結
至此,我們就明白了,正是有了以下兩條的作用,才使得shiro認證註解可以正常work。
<aop:config/>
會掃描配置檔案中的所有advisor,併為其建立代理AuthorizationAttributeSourceAdvisor
匹配所有類,匹配所有加了認證註解的方法