Interceptor,Filter入门

本文介绍了SpringMVC中的Interceptor和JavaWeb中的Filter的概念、执行流程、区别以及在实际开发中的应用,重点讲述了如何使用Interceptor进行JWT令牌的安全验证。
摘要由CSDN通过智能技术生成

前言:在开发中,通常会在访问来到Controller层之前,我们会对请求做一些处(常见的登录功能),在处理完后,再进行决定放行或者时终止访问,同样也会在程序访问后返回到前端时作一些处理(常见的字符集统一,防止出现乱码情况)这个时候就会使用到Interceptor和Filter进行处理。

 一. Interceptor

1.认识拦截器

拦截器是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。

 2.拦截器的执行流程

无拦截器时

af1448ebcf1f4f88b5485af7e70be56a.jpeg

有拦截时

 ff87bf955791485489e1a5601a029794.jpeg

 3.拦截器链(定义多个拦截器,就会形成一个拦截器链)

 8d493e7fa1174d94a299f0e1b8f236aa.jpeg

多个拦截器的执行顺序如下

feacfec991f74254817cf2c36c6604ac.jpeg

 熟悉了以上有拦截器项目的流程以及拦截器链中拦截器的执行顺序后,我们将定义一个拦截器。

4.自定义拦截器(基于springboot项目)

  •  定义拦截器
package com.itheima.Controller.Interceptor;
import com.itheima.Utils.JwtUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**定义一个拦截器*/
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    /**在原始操作之前运行的代码*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
        //true放行
        return true;
    }
    /**在原始操作之后运行的代码*/
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
    /**在原始操作之后运行的代码,并在postHandle之后*/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

 需要定义一个类,并将该类实现HandlerInterceptor接口,重写里面的三个方法。三个方法的简介如下

方法名方法执行顺序
preHandle在原始操作方法之前
postHandle在原始方法操作之后
afterCompletion在postHandle方法操作之后

这三个方法中,return true表示放行,反之,表示拦截到,不放行,返回指定信息。 

  • 配置拦截器  
package com.itheima.Config;
import com.itheima.Controller.Interceptor.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
/**配置方式1*/
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired

    private ProjectInterceptor projectInterceptor;
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
      registry.addResourceHandler("/pages").addResourceLocations("/pages");
    }

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

 这里就配置了一些拦截器要拦截那些访问路经,该类继承了WebMvcConfigurationSupport 类,进行实现的,当然,还有实现方式二如下

package com.itheima.Config;
import com.itheima.Controller.Interceptor.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
/**配置方式二,侵入式较强*/
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired

    private ProjectInterceptor projectInterceptor;
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages").addResourceLocations("/pages");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

里面的逻辑没有任何改动,仅仅是把继承 WebMvcConfigurationSupport 类改为了实现WebMvcConfigurer接口,对比之下,第二种方式的入侵式更强一些。到这里,我们就定义了一个拦截器在项目里面了。

 二.Filter

1.认识过滤器

 它时javaweb的三大组件之一(Servlet程序、Listener监听器、Filter过滤器)

2.过滤器的执行流程

0dbe1088cfb94e77adc67ae6699c020b.jpeg

3.过滤器链(定义多个过滤器,就会形成一个过滤器链)

07b2656c5e53435f93775fd9226da44a.jpeg 

这里,我们可以基于对拦截器链的理解去理解过滤器链。以上对过滤器链认识完之后,我们将定义一个过滤器。

  • 定义过滤器  
package com.itheima.Controller.Filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**定义一个过滤器(javaWeb三大组件之一)*/
@WebFilter(urlPatterns = "/*")
public class ProjectFilter implements Filter {
   /**初始化方法,web服务器启动,创建Filter时调用,只调用一次*/
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    /**每次拦截到请求,调用该方法,调用无数次*/
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                       System.out.println("放行前的逻辑");
                         /**放行*/
                  filterChain.doFilter(servletRequest,servletResponse);
                       System.out.println("放行后的逻辑");
    }
    /**销毁方法,web服务器关闭时调用,只调用一次*/
    @Override
    public void destroy() {

    }
}

  需要定义一个类,并将该类实现Filter接口,重写里面的三个方法。三个方法的简介如下

方法名方法执行顺序
init服务器启动时调用,只执行一次
doFilter每次拦截到请求时调用,执行若干次
destory服务器关闭时调用,只执行一次

在方法内调用  filterChain.doFilter(servletRequest,servletResponse)这句代码,表示放行。方形前后均可以写逻辑处理。@WebFilter(urlPatterns = "/*")表示拦截所有的请求,可根据自己的需求配,到这里过滤器还不能进行生效,它不属于spring管理,所以需要在启动类上加上如下注解。、

package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**过滤器的配置*/
@ServletComponentScan
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

到这里,我们就成功的定义了一个过滤器。 

三. Interceptor,Filter的区别。

1.拦截位置不同,如下图所示

a720750560ba40049de4421569cc3e06.jpeg

二.归属不同

Filter属于Servlet技术,Interceptor属于SpringMVC技术 。

三. 拦截内容不同

Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强。

 四.Jwt令牌实现安全验证(案例) 

 这里我们使用拦截器的方式,过滤器可以自己尝试。这里,只进行逻辑上的一些讲解,并不具体实现。

导入jwt坐标

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

编写一个jwt工具类

import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
/**自定义一个jwt令牌的工具类*/
public class JwtUtils {

    private static String signKey = "itheima";
    private static Long expire = 43200000L;
    /**
     * 生成jwt令牌的方法*/
    public static String generateJwt(Map<String ,Object>  claims){
        String Jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, signKey)         //签名算法
                .setClaims(claims)                                          //自定义数据
                .setExpiration(new Date(System.currentTimeMillis() + expire))               //指定令牌有效期
                .compact();
             return Jwt;

    }
    /**
     * 解析jwt令牌的方法*/
    public static Claims parseJwt(String Jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(Jwt)
                .getBody();
               return claims;
    }

}

对jwt不了解的,可先进行对jwt做个了解。

编写一个接口,用于登录验证 (里面只有逻辑,代码可自行写)

package com.itheima.Controller;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class login {
    /**登录页面
     * 拿到数据进行查询,判断查询出来的数据是否为空,为空返回错误信息,不为空,生成一个jwt令牌,返回给前端,有头部的Token进行存储*/
}

编写一个拦截器,进行相关拦截

package com.itheima.Controller.Interceptor;
import com.itheima.Utils.JwtUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**定义一个拦截器*/
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    /**在原始操作之前运行的代码*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**获取访问的url地址*/
        String toString = request.getRequestURL().toString();
        /**判断该地址是否为登录,为登录,就放行*/
        if(toString.contains("login")){
            return true;
        }
        /**获取Token*/
        String token = request.getHeader("Token");
        /**判断Token是否不存在,不存在返回错误信息*/
        if(!StringUtils.hasLength(token)){
            /**返回错误信息*/

            return false;
        }

        try{
            JwtUtils.parseJwt(token);
        }catch (Exception e){
            /**返回解析错误信息*/
            return false;
        }
        //true放行
        return true;
    }
    /**在原始操作之后运行的代码*/
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
    /**在原始操作之后运行的代码,并在postHandle之后*/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

到这里,我们的jwt令牌的验证就完成了,可自己根据相关提示,把该业务进行完善处理。 

 

 

 

 

 

 

 

 

 

 

 

 

  • 51
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值