filter(过滤器)和interceptor(拦截器)的区别

  1. filter基于filter接口中的doFilter回调函数,interceptor则基于Java本身的反射机制。
  2. filter是依赖于servlet容器的,没有servlet容器就无法回调doFilter方法,而interceptor与servlet无关;
  3. filter的过滤范围比interceptor大,filter除了过滤请求外通过通配符可以保护页面、图片、文件等,而interceptor只能过滤请求,只对action起作用,在action之前开始,在action完成后结束。
  4. filter的过滤一般在加载的时候在init方法声明,而interceptor可以通过在xml声明是guest请求还是user请求来辨别是否过滤;
  5. interceptor可以访问action上下文、值栈里的对象,而filter不能;
  6. 在action的生命周期中,拦截器可以被多次调用,而过滤器只能在容器初始化时被调用一次。

具体实现:

一、Filter:过滤器

启动类需要添加:
@ServletComponentScan(basePackages = “filter路径”)

import com.auth0.jwt.interfaces.Claim;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@WebFilter(filterName = "JwtFilter", urlPatterns = {"/**"})
/**
 * 过滤器,过滤token信息
 * @author lcr
 */
public class JwtFilter implements Filter {

  // 设置的不需要过滤的url
  @Value("${filter.config.excludeUrls}")
  private String excludeUrls;

  @Override
  /**
   * 初始方法
   */
  public void init(FilterConfig filterConfig) throws ServletException {
  }

  @Override
  /**
   * 过滤请求
   */
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws IOException, ServletException {
    final HttpServletRequest request = (HttpServletRequest) req;
    final HttpServletResponse response = (HttpServletResponse) res;
    // 设置响应编码为UTF-8
    response.setCharacterEncoding("UTF-8");
    //获取请求uri
    String url = request.getRequestURI();
    // 判断请求uri是否需要过滤(方法在下面)
    if (excludeUrls.indexOf(url) != -1) {
      // 不需要,放行
      chain.doFilter(request, response);
      return;
    }
    //获取 header里的token
    String token = request.getHeader("sign");
    // 跨域请求options 返回为空
    String str = "OPTIONS";
    if (str.equals(request.getMethod())) {
      response.setStatus(HttpServletResponse.SC_OK);
      return;
    }
    // 除了options跨域请求,都进入到jwt校验
    else {

      if (token == null) {
        response.getWriter().write("没有token!");
        return;
      }
      // 校验接口传进来的token信息
      Map<String, Claim> userData = JwtUtil.verifyToken(token);
      if (userData == null) {
        response.getWriter().write("签名验签失败 !");
        return;
      }
      // 验证请求放行
      chain.doFilter(request, response);
    }
  }

}

二、拦截器

configuration: 拦截器配置

import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author lcr
 * @title: JwtInterceptorConfig
 * @projectName practice_demo
 * @description: 拦截器配置
 * @date 2021/9/9 14:36
 */
@Configuration
public class JwtInterceptorConfig extends WebMvcConfigurationSupport {

  @Resource
  private JwtInterceptor jwtInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 注册拦截器,要声明拦截器对象和要拦截的请求
    registry.addInterceptor(jwtInterceptor)
        //所有路径都被拦截
        .addPathPatterns("/**")
        // 获取token信息
        .excludePathPatterns("/getToken");
  }

}

interceptor:拦截器

import com.auth0.jwt.interfaces.Claim;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * @author lcr
 * @title: JwtInterceptor
 * @projectName practice_demo
 * @description: jwt拦截器
 * @date 2021/9/9 14:30
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    // 设置响应编码为UTF-8
    response.setCharacterEncoding("UTF-8");
    //获取 header里的token
    String token = request.getHeader("sign");
    // 跨域请求options 返回为空
    String str = "OPTIONS";
    if (str.equals(request.getMethod())) {
      response.setStatus(HttpServletResponse.SC_OK);
      return false;
    }// 除了options跨域请求,都进入到jwt校验
    else {
      if (token == null) {
        response.getWriter().write("没有token!");
        return false;
      }
      // 校验接口传进来的token信息
      Map<String, Claim> userData = JwtUtil.verifyToken(token);
      if (userData == null) {
        response.getWriter().write("签名验签失败 !");
        return false;
      }
      return true;
    }
  }
}

工具类

JwtUtils: jwt生成token、验签类。

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JWT工具类
 *
 * @author lcr
 */
public class JwtUtil {

  /**
   * 日志
   */
  private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);
  /**
   * 密钥
   */
  private static final String SECRET = "my_secret";

  /**
   * 过期时间 单位为秒
   **/
  private static final long EXPIRATION = 1800L;

  /**
   * 生成用户token,设置token超时时间
   */
  public static String createToken() {
    //过期时间
    Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
    // 存放head值
    Map<String, Object> map = new HashMap<>();
    map.put("alg", "HS256");
    map.put("typ", "JWT");
    // 加密方式 header payload采用的BASE64加密方式(对称加密) secret采用HMAC(哈希加密)
    String token = JWT.create()
        // 添加头部
        .withHeader(map)
        //可以将基本信息放到claims中
        // 添加载荷PAYLOAD
        // 用户编号
        .withClaim("id", "0001")
        // 用户名称
        .withClaim("userName", "lcr")
        // 超时设置,设置过期的日期
        .withExpiresAt(expireDate)
        // 签发时间
        .withIssuedAt(new Date())
        // sign签名 SECRET加密 采用散列加密
        .sign(Algorithm.HMAC256(SECRET));
    return token;
  }

  /**
   * 校验token并解析token
   */
  public static Map<String, Claim> verifyToken(String token) {
    DecodedJWT jwt = null;
    try {
      // 校验header payload signature是否合法 校验过期时间
      JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
      jwt = verifier.verify(token);
    } catch (Exception e) {
      logger.error(e.getMessage());
      logger.error(" 签名验签失败 !");
      //解码异常则抛出异常
      return null;
    }
    return jwt.getClaims();
  }

}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐