Spring mvc 的拦截器怎么放行一些请求不进行拦截?

配置权限校验和登录校验,日志记录或其他操作,这些都用了Spring MVC的多个拦截器。

但是有一个问题,有一些请求是拦截器不能拦截的,不能进行拦截,否侧会出现异常和错误。比如受信任节点发来的请求,是不用进行权限校验和登录校验的。

拦截器有多个,不可能每一个都写放行判断代码,而且拦截不一定是基于path,可能也是基于请求头。即使是基于类似BaseInterceptor的方式,虽然节省了代码,可还是会执行重复的放行判断的java代码。

spring mvc 有没有一个中间件组件,可以在这里面判断请求是否可以进行拦截或不拦截直接放行?不用进入拦截器的流程?

阅读 402
评论
    2 个回答
    • 1.3k

    我瞎说两句吧。

    首先呢,感觉你的需求广义上来讲也属于认证。参考Spring Security这种认证用过滤器比拦截器更适合。拦截器根据拦截的返回值true/false来决定是否拦截,这样的机制决定了多个拦截器间没有办法直接传递信息。

    但过滤器就不同了,过滤器之间靠过滤器链将多个过滤器连接在一起。我们可以在前置过滤器中对request或response进行装饰(当然可以把一些自定义的信息装饰进去了),然后再在后置过滤器中获取装饰过的request或reponse,再根据获取的值来进行一些逻辑处理。

    比如我们在第一个过滤器的request新建一个authed请求头,默认值给false。然后第一个过滤器中再加入这样的逻辑:

    1. 获取 authed请求头,如果值为true,则直接放行。
    2. 如果值为false,则执行自己的认证逻辑。
      2.1 如果逻辑通过,则设置authed为true
      2.2 继续执行过滤链上的下一个过滤器。
      • *

    如果说你的当前业务必须使用拦截器,建议尝试以下思路。

    1. 建立接口 InterceptorToken
    2. 为实际业务已存在的多个拦截器(下文中假设有两个,分别为A、B)建立接口 Xxxxoken,比如AInterceptorToken、BInterceptorToken,全部继承 InterceptorToken。
    3. 建立一个作用域为当前请求的Service
    @Service
    @Scope(WebApplicationContext.SCOPE_REQUEST)
    class public TokenContainer() {
        List<InterceptorToken> tokens = new ArrayList<InterceptorToken>;
        public void addToken(InterceptorToken token) {
            // 在此还可以加入token类型是否存在的验证
            this.tokens.add(token);
        }
        
        /**
        * 判断token是否存在
        * 没有实际运行,代码可能写的不对
        **/
        public boolean exists(class<InterceptorToken> token) {
            // ....
        }
    }

    再然后:

    1. 在第一个拦截器执行以前:获取请求信息,判断是否为受信任节点发来的请求或者其它你认为不需要再拦截在请求。
    2. 如果不想让A拦截,则addToken(AInterceptorToken)
    3. 如果同时不想让B拦截,再addToken(BInterceptorToken)
    4. 在A拦截器中增加:if(tokenContainer.exists(AInterceptorToken.class) then 不拦截
    5. 在B拦截器中增加:if(tokenContainer.exists(BInterceptorToken.class) then 不拦截
    6. 如果你需要一个让所有拦截器都不拦截的功能,则还可以建立一个GobalInterceptorToken,然后将A拦截器的中的代码改为:if(tokenContainer.exists(GobalInterceptorToken.class || AInterceptorToken.class) then 不拦截

    希望对你有帮助。

    Java旅途 的答案和我的答案可能都不是你想要的。但我们都是出于热心,我们可以接受你不回复、不评论。但如果回复或是评论我想我们还是希望能看到是更多的相互尊重与真诚的态度。毕竟在思否这个平台上,谁都没有帮助谁的业务。

      写个白名单数组进行过滤吧,比如下面这样

      // 不需要拦截的请求,可以根据实际需求切换为请求头的某个参数值
      private static final String[] whiteList = {"/oauth/token","/captchaImage"};
      
      // 跳过不需要验证的路径
      if (Arrays.asList(whiteList).contains(url)){
         // 调用逻辑方法,处理业务 
      }else {
         // 拦截器处理请求 
      }
        撰写回答

        登录后参与交流、获取后续更新提醒

        相似问题
        推荐文章