@Configuration
@Import(ShiroAnnotationProcessorConfiguration.class)
public class ShiroConfig {
}
// 注册注解的处理器,根据授权认证注解需要生成代理对象的后置处理器
public class ShiroAnnotationProcessorConfiguration {
@Bean
@DependsOn("lifecycleBeanPostProcessor")
protected DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
// 创建代理对象的BeanPostProcessor
return new DefaultAdvisorAutoProxyCreator();
}
@Bean
protected AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
// 注解解析的切面
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
// 授权认证注解需要生成代理对象的切面,会根据是否存在注解来确定该切面是否可以应用上该切面
public class AuthorizationAttributeSourceAdvisor {
// 当前切面需要运用的拦截器
private Advice advice = EMPTY_ADVICE;
// 支持的授权认证注解
private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
new Class[]{RequiresPermissions.class,
RequiresRoles.class,
RequiresUser.class,
RequiresGuest.class,
RequiresAuthentication.class};
public AuthorizationAttributeSourceAdvisor() {
setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
// 匹配当前切面是否可用,只要类,方法,父类,实现的接口,实现的接口方法中包含授权注解,都匹配成功
public boolean matches(Method method, Class targetClass) {
Method m = method;
// 当前执行的方法中是否存在授权相关注解
if (this.isAuthzAnnotationPresent(m)) {
return true;
}
// 当前执行的方法中不存在授权注解,继续找接口或者
if (targetClass != null) {
// 获取父类方法(父类),接口方法(接口)是否存在授权注解
m = targetClass.getMethod(m.getName(), m.getParameterTypes());
return this.isAuthzAnnotationPresent(m) || this.isAuthzAnnotationPresent(targetClass);
}
return false;
}
// 判断方法中或者类中是否存在授权注解
private boolean isAuthzAnnotationPresent(AnnotatedElement element) {
for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = AnnotationUtils.findAnnotation(element, annClass);
// 如果存在返回true
if (a != null) {
return true;
}
}
return false;
}
}
// 注解代理对象的统一拦截器入口,内部代理了具体的注解拦截器的处理逻辑
public class AopAllianceAnnotationsAuthorizingMethodInterceptor {
// 当前拦截器代理的5个注解相关处理的拦截器
protected Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors;
public AopAllianceAnnotationsAuthorizingMethodInterceptor() {
List<AuthorizingAnnotationMethodInterceptor> interceptors = new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);
// 注解解析器
AnnotationResolver resolver = new SpringAnnotationResolver();
// 添加处理RequiresRoles的拦截器
interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
// 添加处理RequiresPermissions的拦截器
interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
// 添加处理RequiresAuthentication的拦截器
interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
// 添加处理RequiresUser的拦截器
interceptors.add(new UserAnnotationMethodInterceptor(resolver));
// 添加处理RequiresGuest的拦截器
interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
this.methodInterceptors = interceptors;
}
// 代理的拦截方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
// 断言授权
this.assertAuthorized(mi);
// 继续执行下一个拦截器
return mi.proceed();
}
protected void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException {
Collection<AuthorizingAnnotationMethodInterceptor> aamis = this.methodInterceptors;
// 如果存在处理注解的拦截器
if (aamis != null && !aamis.isEmpty()) {
// 遍历所有支持的拦截器
// AuthorizingAnnotationMethodInterceptor为具体拦截器的父类
for (AuthorizingAnnotationMethodInterceptor aami : aamis) {
// 只要支持处理该注解的拦截器都会执行
if (aami.supports(methodInvocation)) {
// 执行授权认证的断言操作
aami.assertAuthorized(methodInvocation);
}
}
}
}
}
// 授权注解的通用方法拦截器
public class AuthorizingAnnotationMethodInterceptor {
public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
try {
// 执行handler的处理逻辑,这个Handler在创建对应注解的拦截器就已经设置好固定处理注解的Handler
AuthorizingAnnotationHandler handler = (AuthorizingAnnotationHandler) getHandler();
// 使用具体的注解处理器进行断言
handler.assertAuthorized(getAnnotation(mi);
} catch (AuthorizationException ae) {
if (ae.getCause() == null) {
ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
}
throw ae;
}
}
}
// 解释两个,处理RequiresAuthentication注解,处理RequiresRoles注解
// 处理RequiresRoles注解
public class RoleAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
// RequiresRoles注解指定处理器
public RoleAnnotationMethodInterceptor() {
super(new RoleAnnotationHandler());
}
}
// 授权注解的通用处理器
public class AuthorizingAnnotationHandler {
// 授权注解的处理器,需要传递该Handler需要处理的注解
public AuthorizingAnnotationHandler(Class<? extends Annotation> annotationClass) {
super(annotationClass);
}
// 根据具体的注解进行断言的方法
public abstract void assertAuthorized(Annotation a) throws AuthorizationException;
}
// 处理RequiresRoles注解的处理器
public class RoleAnnotationHandler extends AuthorizingAnnotationHandler {
public RoleAnnotationHandler() {
super(RequiresRoles.class);
}
// 断言
public void assertAuthorized(Annotation a) throws AuthorizationException {
// 如果不存在RequiresRoles注解,不处理
if (!(a instanceof RequiresRoles)) {
return;
}
// 获取注解中的角色信息
RequiresRoles rrAnnotation = (RequiresRoles) a;
String[] roles = rrAnnotation.value();
// 如果只有一个,直接调用Suject的校验权限方法
if (roles.length == 1) {
/**
* <pre>
* 校验流程
* 1. 先判断是否认证,如果没有认证,抛出认证异常
* 2. 在调用securityManager(为AuthorizingSecurityManager的子类)的校验方法
* 2.1 在该securityManager包含一个Authorizer授权器,该类型为ModularRealmAuthorizer
* 2.2 最终是调用ModularRealmAuthorizer.hasRoles方法
* 3. 断言ModularRealmAuthorizer设置的Realm是否为空(必须存在一个Realm才行)
* 4. 遍历所有的授权Realm(实现了Authorizer的Realm,一般都是AuthorizingRealm),调用Realm的hasRole方法
* 5. 获取该用户的授权信息,先根据用户查缓存,如果不存在,调用Realm的doGetAuthorizationInfo方法获取权限并缓存
* 6. 最终从获取的权限信息中,判断是否存在指定的权限,如果不存在抛出UnauthorizedException异常
* </pre>
*/
getSubject().checkRole(roles[0]);
return;
}
// 一些表达式的授权逻辑,和上面的逻辑一样
// AND运算符,必须同时拥有多个权限
if (Logical.AND.equals(rrAnnotation.logical())) {
getSubject().checkRoles(Arrays.asList(roles));
return;
}
// OR运算符,只需要拥有其中一个权限
if (Logical.OR.equals(rrAnnotation.logical())) {
boolean hasAtLeastOneRole = false;
for (String role : roles) {
if (getSubject().hasRole(role)) {
hasAtLeastOneRole = true;
}
}
if (!hasAtLeastOneRole) {
getSubject().checkRole(roles[0]);
}
}
}
}
// 处理RequiresAuthentication注解的处理器
public class AuthenticatedAnnotationHandler extends AuthorizingAnnotationHandler {
public AuthenticatedAnnotationHandler() {
super(RequiresAuthentication.class);
}
// 断言
public void assertAuthorized(Annotation a) throws UnauthenticatedException {
// 如果Subject没有进行认证,抛出异常
if (a instanceof RequiresAuthentication && !getSubject().isAuthenticated()) {
throw new UnauthenticatedException("The current Subject is not authenticated. Access denied.");
}
}
}
// 处理RequiresAuthentication注解
public class AuthenticatedAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
// RequiresAuthentication注解指定处理器
public AuthenticatedAnnotationMethodInterceptor(AnnotationResolver resolver) {
super(new AuthenticatedAnnotationHandler(), resolver);
}
}
Shiro注解认证授权实现原理
于 2024-05-14 12:14:13 首次发布