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")[];
}
} //验证token是否有效
boolean checkToken = this.checkToken(token, pageId);
if (!checkToken) {
//未登录就跳转到登录页面
//response.sendRedirect(LOGIN_HOST + "login");
Result<String> resultObject = Result.fail("", "登录超时,请刷新页面重新登录");
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() != || 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")[]);
}
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, * );
return writer.getBuffer().toString();
} finally {
writer.close();
}
} private long write(Reader reader, Writer writer, int bufferSize) throws IOException {
int read;
long total = ;
char[] buf = new char[bufferSize];
while ((read = reader.read(buf)) != -) {
writer.write(buf, , read);
total += read;
}
return total;
} }

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);
}
}

Spring Boot拦截器实现并和swagger集成后使用拦截器的配置问题的更多相关文章

  1. Spring Boot干货系列:(六)静态资源和拦截器处理

    Spring Boot干货系列:(六)静态资源和拦截器处理 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 本章我们来介绍下SpringBoot对静态资源的支持以及很重要的一个类We ...

  2. Spring boot中使用springfox来生成Swagger Specification小结

    Rest接口对应Swagger Specification路径获取办法: 根据location的值获取api   json描述文件 也许有同学会问,为什么搞的这么麻烦,api json描述文件不就是h ...

  3. Spring Boot 2.x基础教程:Swagger静态文档的生成

    前言 通过之前的两篇关于Swagger入门以及具体使用细节的介绍之后,我们已经能够轻松地为Spring MVC的Web项目自动构建出API文档了.如果您还不熟悉这块,可以先阅读: Spring Boo ...

  4. 解决Spring Boot 从1.x升级到 2.x 后 单点登陆(SSO)问题

    解决Spring Boot 从1.x升级到 2.x 后 单点登陆(SSO)问题   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring S ...

  5. 【转】Spring Boot干货系列:(六)静态资源和拦截器处理

    前言 本章我们来介绍下SpringBoot对静态资源的支持以及很重要的一个类WebMvcConfigurerAdapter. 正文 前面章节我们也有简单介绍过SpringBoot中对静态资源的默认支持 ...

  6. Spring Boot 2.x基础教程:Swagger接口分类与各元素排序问题详解

    之前通过Spring Boot 2.x基础教程:使用Swagger2构建强大的API文档一文,我们学习了如何使用Swagger为Spring Boot项目自动生成API文档,有不少用户留言问了关于文档 ...

  7. Spring Boot 2.x以后static下面的静态资源被拦截

    今天创建一个新的Spring Boot项目,没注意到spring boot的版本,发现静态资源无法访问.百度一下发现好像是Spring Boot 2.0版本以后static目录不能直接访问. 接下来直 ...

  8. Spring Boot(十三)RabbitMQ安装与集成

    一.前言 RabbitMQ是一个开源的消息代理软件(面向消息的中间件),它的核心作用就是创建消息队列,异步接收和发送消息,MQ的全程是:Message Queue中文的意思是消息队列. 1.1 使用场 ...

  9. Spring Boot学习笔记(二二) - 与Mybatis集成

    Mybatis集成 Spring Boot中的JPA部分默认是使用的hibernate,而如果想使用Mybatis的话就需要自己做一些配置.使用方式有两种,第一种是Mybatis官方提供的 mybat ...

随机推荐

  1. 项目Beta冲刺 - 凡事预则立

    课程: 软件工程1916|W(福州大学) 作业要求: 项目Beta冲刺 团队名称: 火鸡堂 作业目标: 尽力交付 火鸡堂 队员学号 队员姓名 博客地址 备注 221600111 彼术向 http:// ...

  2. PHP隐藏IP地址末位的方法

    很久之前写过一个使用ASP隐藏IP地址末位的文章,也就是有时候为了保护用户的隐私,会隐藏用户的IP地址,达成类似于 222.222.222.* 的效果.  现在想要用PHP来实现,经过尝试,其实非常简 ...

  3. 修改idea,webstrom,phpstrom 快捷键double shift 弹出search everywhere

    这个问题很困惑,因为这个功能很好用,查找什么很方便,but! 我用了十年的搜狗输入法,大家都知道搜狗输入法按shift中英文切换很方便,特别在写代码时候...所以就和这个double shift功能冲 ...

  4. js去除数组中重复的数字

    var arr = [2,1,4,3,2,4,2,3,4,2,6,5,5] var obj = {}; var arrNew = []; for(var i=arr.length-1;i>=0; ...

  5. 利用GitHub+Node.js+Hexo搭建个人博客

    本篇是自己在搭建Hexo博客平台时的一个过程记录.(2019.9.13实测有效) GitHub 账号注册 因为此文所搭建的个人博客是基于GitHub平台服务的,所以首先是注册GitHub,当然已有账号 ...

  6. 调用图灵API V2 遇到的坑

    1:遇到的第一个问题:跨域 解决办法: 第一种:使用query中的jsonp 可惜图灵要求post方法,而jsonp,只能使用get方法,才能跨域,失败 第二种:服务器添加header,可是我怎么去改 ...

  7. rhcsa备战笔记

    笔记全部手打 转载请加原文链接 0)重置密码开机按e 找到linux16行 rd.break console=tty0  ctrl+xmount -o remount,rw /sysrootchroo ...

  8. .net core 多sdk 多版本 环境切换

    在讲述.net core多版本之前,我们先理解一下.net core sdk与.net core runtime之前的联系与区别,根据官网的解释我们可以简单地理解为:sdk是在开发过程中进行使用,而r ...

  9. Python爬虫进阶 | 多线程

    一.简介 为了提高爬虫程序效率,由于python解释器GIL,导致同一进程中即使有多个线程,实际上也只会有一个线程在运行,但通过request.get发送请求获取响应时有阻塞,所以采用了多线程依然可以 ...

  10. PostGraphile 4.4 发布,支持real time 查询

    在4.4 之前,real time 是通过插件完成处理的,4.4 直接内置了,还是很方便的功能,总算 和其他类似graphql 平台看齐了,使用上还是挺方便的. 参考资料 https://www.gr ...