使用spring的AOP时候,想要过滤掉某些路径或者忽略指定注解,怎么做?

  • 作者: 凯哥Java(公众号:凯哥Java)
  • shiro学习系列
  • 时间:2024-05-30 16:01
  • 195人已阅读
简介 背景:项目使用shiro做安全框架的。现在需要使用SpringAOP切面记录日志。切入点:  @Pointcut("execution(public*com.kaigejava.business..controller..*.*(..))")这样配置会有问题。因为有些地方需要忽略shiro认证。比如在shiroConfig中,我配置了很多。如下: 

🔔🔔好消息!好消息!🔔🔔

 如果您需要注册ChatGPT,想要升级ChatGPT4。凯哥可以代注册ChatGPT账号代升级ChatGPT4

有需要的朋友👉:微信号 kaigejava2022

背景:

项目使用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);
        }
    }
}


解释

  1. 切入点表达式

    • @Pointcut("execution(public * com.kaigejava.business..controller..*.*(..))"):匹配controller包及其子包中的所有public方法。

    • @Pointcut("!@within(com.kaigejava.shiro.ShiroIgnoreAuth) && !@annotation(com.kaigejava.shiro.ShiroIgnoreAuth)"):排除带有ShiroIgnoreAuth注解的类或方法。

  2. 动态排除路径

    • before方法中,获取当前请求的URI。

    • 定义需要排除的路径列表。

    • 检查当前请求是否在排除路径中,如果在,则直接返回,不执行后续逻辑。

  3. 路径匹配实现

    • pathMatches方法实现了简单的路径匹配逻辑,支持/**通配符。


知识点:

在 Spring AOP 中,直接获取 HttpServletRequest 是不容易的,因为切面方法并不直接处理 HTTP 请求。为了解决这个问题,我们可以通过 Spring 的 RequestContextHolder 来获取当前的请求。

以下是修改后的完整示例,包括使用 RequestContextHolder 来获取 HttpServletRequest



TopTop