Spring Boot拦截器实现并和swagger集成后使用拦截器的配置问题

1. 定义拦截器 LoginInterceptor

LoginInterceptor.java是整个登录认证模块中的核心类之一,它实现了HandlerInterceptor类,由它来拦截并过滤到来的每一个请求;它的三个方法能分别作用于每个请求的不同生命周期,你可以根据自己的需要来加入相应的处理逻辑

package com.demo.common.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * @ProjectName: demo
 * @Package: com.demo.common.interceptor
 * @ClassName: LoginInterceptor
 * @Description: 登录请求拦截器
 * @Author:
 * @Date: 
 * @Version: 1.0
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

  /**
   * 在请求被处理之前调用
   * @param request
   * @param response
   * @param handler
   * @return
   * @throws Exception
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    String requestMethod = request.getMethod();
    if (requestMethod.contains("OPTIONS") || requestMethod.contains("options")) {
      return true;
    }

    //token 校验
    String token = request.getHeader("token");
    if (StringUtil.isEmpty(token)) {
      token = request.getHeader("token-inc");
    }

    //获取请求页面id
    String pageId = "";
    Map<String, String[]> paramMap = request.getParameterMap();
    if (CollectionUtils.isNotEmpty(paramMap)) {
      if (paramMap.containsKey("page_id")) {
        pageId = paramMap.get("page_id")[0];
      }
    }

    //验证token是否有效
    boolean checkToken = this.checkToken(token, pageId);
    if (!checkToken) {
      //未登录就跳转到登录页面
      //response.sendRedirect(LOGIN_HOST + "login");
      Result<String> resultObject = Result.fail("10001", "登录超时,请刷新页面重新登录");
      PrintWriter writer = response.getWriter();
      writer.write(JSON.toJSONString(resultObject));
      writer.flush();
      writer.close();
      return false;
    }

    //参数日志打印
    if (handler instanceof HandlerMethod) {
      this.saveRequestLog(request);
    }
    return true;
  }

  /**
   * 在请求被处理后,视图渲染之前调用
   * @param request
   * @param response
   * @param handler
   * @param modelAndView
   * @throws Exception
   */
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    //Collection<String> headerNames = response.getHeaderNames();
    //log.info("[postHandle]{}", JsonUtils.toJson(headerNames));
  }

  /**
   * 在整个请求结束后调用
   * @param request
   * @param response
   * @param handler
   * @param ex
   * @throws Exception
   */
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    UserInfoHolder.removeUserInfo();
  }

  /**
   * 请求校验token 塞入ThreadLocal
   *
   * @param token
   * @return
   */
  private boolean checkToken(String token, String pageId) {
    //不需要验证,直接通过,使用于直接请求接口(测试用)
    if ("false".equals(ENABLE_TOKEN) || NOT_VAILE_TOKEN.equals(token)) {
      return true;
    }

    if (StringUtil.isEmpty(token)) {
      return false;
    }

    //请求获取登录用户信息及权限
    HttpBO<UserInfoBO> httpBO = this.httpUserInfo(token, pageId);

    if (httpBO == null || httpBO.getCode() == null || httpBO.getCode() != 0 || httpBO.getData() == null) {
      return false;
    }

    this.saveLoginContext(httpBO.getData());

    return true;
  }

  private HttpBO<UserInfoBO> httpUserInfo(String token, String pageId) {
    HttpBO<UserInfoBO> httpBO = new HttpBO<>();
    try {
      LoginQuery loginQuery = new LoginQuery();
      loginQuery.setCookieStr(token);
      loginQuery.setPageId(pageId);
      String url = API_HOST + USER_URL;
      String jsonUserInfoBo = JSON.toJSONString(loginQuery);
      log.info("发送请求获取权限参数信息 param:{},url:{}", jsonUserInfoBo, url);
      String response = HttpClientPostUtil.sendPostRequest(url, jsonUserInfoBo);
      log.info("发送请求获取权限返回信息 response={}", response);
      Type type = new TypeReference<HttpBO<UserInfoBO>>() {
      }.getType();
      httpBO = JSON.parseObject(response, type);
      //httpBO = JSON.parseObject(response, new HttpBO<UserInfoBO>().getClass());
      log.info("发送请求获取权限信息 封装 httpBO:{}", JSON.toJSONString(httpBO));     
    } catch (Exception ex) {
      log.error("发送请求获取权限失败 error:{}", ex.getMessage());     
    }
    return httpBO;
  }

  private void saveLoginContext(UserInfoBO userInfoBO) {
    //List<ButtonBO> buttonBOList = userInfoBO.getUserBtns();
    //if (CollectionUtils.isEmpty(buttonBOList)) {
    //  List<String> code = buttonBOList.stream().map(ButtonBO::getBtnCode).collect(Collectors.toList());
    //}

    UserInfoHolder.setUserInfo(userInfoBO);
  }

  private void saveRequestLog(HttpServletRequest request) throws Exception {
    StringBuilder builder = new StringBuilder();
    builder.append("请求入口 ");
    builder.append("PATH => ");
    builder.append(request.getRequestURI());
    builder.append(",METHOD => ");
    builder.append(request.getMethod());
    builder.append(",PARAM => ");
    Map<String, String[]> paramMap = request.getParameterMap();
    if (CollectionUtils.isNotEmpty(paramMap)) {
      builder.append(JSON.toJSONString(paramMap));
      builder.append(",page_id => ");
      if (paramMap.containsKey("page_id")) {
        builder.append(paramMap.get("page_id")[0]);
      }
      log.info(builder.toString());
      return;
    }
    if (request instanceof MultipartHttpServletRequest) {
      log.info(builder.toString());
      return;
    }
    //由于request.getReader流只能操作一次,这里用过一次后,在Control中获取RequestBody中参数就获取不到,所以这里要先注释掉,后续解决
//    BufferedReader reader = request.getReader();
//    String body = this.read(reader);
//    if (StringUtil.isNotEmpty(body)) {
//      body = body.replace("\n", "");
//    }
//    builder.append(body);
    log.info(builder.toString());
  }

  private String read(Reader reader) throws IOException {
    StringWriter writer = new StringWriter();
    try {
      this.write(reader, writer, 1024 * 8);
      return writer.getBuffer().toString();
    } finally {
      writer.close();
    }
  }

  private long write(Reader reader, Writer writer, int bufferSize) throws IOException {
    int read;
    long total = 0;
    char[] buf = new char[bufferSize];
    while ((read = reader.read(buf)) != -1) {
      writer.write(buf, 0, read);
      total += read;
    }
    return total;
  }

}
View Code

2. 注册拦截器配置 LoginConfiguration

LoginConfiguration.java是另一个核心类之一,它继承自WebMvcConfigurer类,负责注册并生效我们自己定义的拦截器配置;在这里要注意定义好拦截路径和排除拦截的路径;

package com.demo.common.configuration;

import com.demo.common.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.MappedInterceptor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @ProjectName: demo
 * @Package: com.demo.common.configuration
 * @ClassName: LoginConfiguration
 * @Description: 负责注册并生效自己定义的拦截器配置
 * @Author:
 * @Date: 
 * @Version: 1.0
 */
@Configuration
public class LoginConfiguration implements WebMvcConfigurer {
  @Bean
  public MappedInterceptor getMappedInterceptor() {
    //注册拦截器
    LoginInterceptor loginInterceptor = new LoginInterceptor();
    //拦截路径 ("/**")对所有请求都拦截
    String[] includePatterns = new String[]{"/**"};
    //排除拦截路径
    String[] excludePatterns = new String[]{"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**",
      "/api", "/api-docs", "/api-docs/**"};

    //将数组转化为集合
    List<String> listOldExclude = Arrays.asList(excludePatterns);

    //将自定义的排除拦截路径添加到集合中
    List<String> listNewExclude = new ArrayList<>();
    listNewExclude.add("/demoJson/getCityList.json");
    listNewExclude.add("/demoJson/getStudentList.json");
    
    //定义新集合
    List<String> listExclude = new ArrayList<>();
    listExclude.addAll(listOldExclude);
    listExclude.addAll(listNewExclude);

    //将新集合转化回新数组
    String[] newExcludePatterns = listExclude.toArray(new String[listExclude.size()]);

    return new MappedInterceptor(includePatterns, newExcludePatterns, loginInterceptor);
  }
}
View Code
posted @ 2019-12-20 11:04  以德为先  阅读(3449)  评论(0编辑  收藏  举报