问题
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
我们注意到有个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
匹配所有类,匹配所有加了认证注解的方法