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 @   以德为先  阅读(3465)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示