使用spring的AOP时候,想要过滤掉某些路径或者忽略指定注解,怎么做?
- shiro学习系列
- 时间:2024-05-30 16:01
- 1926人已阅读
🔔🔔好消息!好消息!🔔🔔
有需要的朋友👉:微信号
背景:
项目使用shiro做安全框架的。现在需要使用Spring AOP切面记录日志。
切入点:
@Pointcut("execution(public * com.kaigejava.business..controller..*.*(..))")
这样配置会有问题。因为有些地方需要忽略shiro认证。比如在shiroConfig中,我配置了很多。如下:
filterChainDefinitionMap.put("/diagram-viewer/**", "anon");
filterChainDefinitionMap.put("/editor-app/**", "anon");
filterChainDefinitionMap.put("/riskNotificationLetter/download/**", "anon"); //草稿箱下载权限放开
filterChainDefinitionMap.put("/login/toLogin", "anon");
filterChainDefinitionMap.put("/homePageSimulationData/**", "anon");
filterChainDefinitionMap.put("/synchronizationEdataController/**", "anon");
filterChainDefinitionMap.put("/dayReportController/**", "anon");
同时我在JwtFilter中配置了
//校验类上有没有此注解。如果类类存在此注解,整个类的url都不会被拦截
ShiroIgnoreAuth anonymousAccess = AnnotationUtils.getAnnotation(nowClass, ShiroIgnoreAuth.class);
那么我上面的的切入点表达式应该怎么写?
1. 基于路径排除
使用within来指定包,并且使用@annotation或!@annotation来排除带有特定注解的方法。由于你列出的路径在AOP切面中无法直接匹配(因为路径是URL模式,而不是Java包路径),你需要在AOP切面中手动添加排除逻辑。
2. 排除带有注解的类或方法
你可以在AOP中检查方法或类是否带有特定注解,然后根据需要进行处理。
切入点表达式
要只切入controller包中的方法,同时排除特定路径和注解,你可以结合使用多个切入点表达式。
示例代码:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
@Aspect
@Component
public class MyAspect {
@Autowired
private HttpServletRequest request;
// 切入com.kaigejava.business包及其子包下的controller包中的所有public方法
@Pointcut("execution(public * com.kaigejava.business..controller..*.*(..))")
public void controllerMethods() {
}
// 排除带有ShiroIgnoreAuth注解的类或方法
@Pointcut("!@within(com.kaigejava.shiro.ShiroIgnoreAuth) && !@annotation(com.kaigejava.shiro.ShiroIgnoreAuth)")
public void excludeAnnotatedMethods() {
}
// 组合切入点:排除注解的方法
@Pointcut("controllerMethods() && excludeAnnotatedMethods()")
public void combinedPointcut() {
}
@Before("combinedPointcut()")
public void before(JoinPoint joinPoint) {
// 获取当前请求的URI
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String requestUri = request.getRequestURI();
// 定义需要排除的路径
String[] excludePaths = {
"/diagram-viewer/**",
"/editor-app/**",
"/riskNotificationLetter/download/**",
"/login/toLogin",
"/homePageSimulationData/**",
"/synchronizationEdataController/**",
"/dayReportController/**",
"/safetyRegulationsFile/**",
"/risk/file/download/**",
"/gis/sensorLogTrendExcel",
"/gis/download",
"/login/login",
"/**/fileDownload",
"/specialKnowledge/export",
"/risk/camera/importexcel",
"/workticket/ticketListExcel",
"/breakrule/export",
"/projectRisk/fileDownload",
"/riskLeanManagement/export",
"/login/initUserPassword",
"/",
"/doc.html",
"/**/*.js",
"/**/*.css",
"/**/*.html",
"/**/*.svg",
"/**/*.pdf",
"/**/*.jpg",
"/**/*.png",
"/**/*.txt",
"/**/*.ico",
"/*",
"/druid/**",
"/swagger-ui.html",
"/swagger**/**",
"/v3/**",
"/v2/**"
};
// 检查当前请求是否在排除路径中
for (String excludePath : excludePaths) {
if (pathMatches(requestUri, excludePath)) {
return; // 排除路径,直接返回,不执行后续逻辑
}
}
// TODO 执行切面逻辑
}
private boolean pathMatches(String requestUri, String excludePath) {
// 简单的路径匹配实现,具体可以根据需要进行增强
if (excludePath.endsWith("/**")) {
String basePath = excludePath.substring(0, excludePath.length() - 3);
return requestUri.startsWith(basePath);
} else {
return requestUri.equals(excludePath);
}
}
}解释
切入点表达式:
@Pointcut("execution(public * com.kaigejava.business..controller..*.*(..))"):匹配controller包及其子包中的所有public方法。@Pointcut("!@within(com.kaigejava.shiro.ShiroIgnoreAuth) && !@annotation(com.kaigejava.shiro.ShiroIgnoreAuth)"):排除带有ShiroIgnoreAuth注解的类或方法。动态排除路径:
在
before方法中,获取当前请求的URI。定义需要排除的路径列表。
检查当前请求是否在排除路径中,如果在,则直接返回,不执行后续逻辑。
路径匹配实现:
pathMatches方法实现了简单的路径匹配逻辑,支持/**通配符。
知识点:
在 Spring AOP 中,直接获取 HttpServletRequest 是不容易的,因为切面方法并不直接处理 HTTP 请求。为了解决这个问题,我们可以通过 Spring 的 RequestContextHolder 来获取当前的请求。
以下是修改后的完整示例,包括使用 RequestContextHolder 来获取 HttpServletRequest,