自定义Shiro注解
顺序
- 创建自定义的注解
- 资源管理器,继承
AuthorizationAttributeSourceAdvisor
,添加新注解支持 - AOP拦截器,继承
AopAllianceAnnotationsAuthorizingMethodInterceptor
- 方法拦截器,继承
AuthorizingAnnotationMethodInterceptor
- 权限处理器,继承
AuthorizingAnnotationHandler
,校验权限
一、自定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Permissions {
String[] value();
}
二、权限处理器
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
import org.apache.shiro.subject.Subject;
import java.lang.annotation.Annotation;
/**
* 自定义权限处理器
* @author BBF
*/
public class PermissionHandler extends AuthorizingAnnotationHandler {
public PermissionHandler() {
super(Permissions.class);
}
@Override
public void assertAuthorized(Annotation a) throws AuthorizationException {
if (a instanceof Permissions) {
Permissions annotation = (Permissions) a;
String[] perms = annotation.value();
Subject subject = getSubject();
if (perms.length == 1) {
subject.checkPermission(perms[0]);
return;
}
// 多个权限,有一个就通过
boolean hasAtLeastOnePermission = false;
for (String permission : perms) {
if (subject.isPermitted(permission)) {
hasAtLeastOnePermission = true;
break;
}
}
// Cause the exception if none of the role match,
// note that the exception message will be a bit misleading
if (!hasAtLeastOnePermission) {
subject.checkPermission(perms[0]);
}
}
}
}
三、方法拦截器
import org.apache.shiro.aop.AnnotationResolver;
import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
/**
* 自定义注解的方法拦截器
* @author BBF
*/
public class PermissionMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
public PermissionMethodInterceptor() {
super(new PermissionHandler());
}
public PermissionMethodInterceptor(AnnotationResolver resolver) {
super(new PermissionHandler(), resolver);
}
@Override
public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
// 验证权限
try {
((PermissionHandler) getHandler()).assertAuthorized(getAnnotation(mi));
} catch (AuthorizationException ae) {
// Annotation handler doesn't know why it was called, so add the information here if possible.
// Don't wrap the exception here since we don't want to mask the specific exception, such as
// UnauthenticatedException etc.
if (ae.getCause() == null) {
ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
}
throw ae;
}
}
}
四、切面拦截器
import org.apache.shiro.spring.aop.SpringAnnotationResolver;
import org.apache.shiro.spring.security.interceptor.AopAllianceAnnotationsAuthorizingMethodInterceptor;
/**
* 自定义注解的AOP拦截器
* @author BBF
*/
public class PermissionAopInterceptor extends AopAllianceAnnotationsAuthorizingMethodInterceptor {
public PermissionAopInterceptor() {
super();
// 添加自定义的注解拦截器
this.methodInterceptors.add(new PermissionMethodInterceptor(new SpringAnnotationResolver()));
}
}
五、注解拦截器
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.springframework.core.annotation.AnnotationUtils;
import java.lang.reflect.Method;
/**
* 自定义的Shiro注解拦截器
* @author BBF
*/
public class ShiroAdvisor extends AuthorizationAttributeSourceAdvisor {
/**
* Create a new AuthorizationAttributeSourceAdvisor.
*/
public ShiroAdvisor() {
// 这里可以添加多个
setAdvice(new PermissionAopInterceptor());
}
@SuppressWarnings({"unchecked"})
@Override
public boolean matches(Method method, Class targetClass) {
Method m = method;
if (targetClass != null) {
try {
m = targetClass.getMethod(m.getName(), m.getParameterTypes());
return this.isFrameAnnotation(m);
} 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 super.matches(method, targetClass);
}
private boolean isFrameAnnotation(Method method) {
return null != AnnotationUtils.findAnnotation(method, Permissions.class);
}
}
六、配置shiro
替换AuthorizationAttributeSourceAdvisor
为 ShiroAdvisor
/**
* 启用注解拦截方式
* @return AuthorizationAttributeSourceAdvisor
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor advisor = new ShiroAdvisor();
advisor.setSecurityManager(securityManager());
return advisor;
}