SpringBoot :API接口拦截器验证(Token验证)并将数据存入Request中供接口调用

您所在的位置:网站首页 spring拦截器 SpringBoot :API接口拦截器验证(Token验证)并将数据存入Request中供接口调用

SpringBoot :API接口拦截器验证(Token验证)并将数据存入Request中供接口调用

2023-07-17 09:47| 来源: 网络整理| 查看: 265

一、为什么需要拦截器?

在前后端分离的现在,项目中的所有的前端的页面都需要通过调用后台的Api进行获取数据 接口的功能点不同,就会有很多种情况,比如说

涉及敏感数据(登录,获取个人信息,个人金额修改)相关的接口需要token验证获取不敏感数据则不需要进行校验vue等前端调用后台api,如果没有引入(nginx),则有可能有跨域问题

所以说需要一个拦截器去区分哪些路径下需要token校验,那些不需要。

二、实现思路 新增一个配置类继承WebMvcConfigurer在这个配置类中新增自定义逻辑的拦截器(实现HandlerInterceptor接口),同时设定哪些路径需要调用自定义拦截器 三、具体代码实现(示例代码:https://github.com/zz790609619/LeetCodeRecord.git)

配置类

package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.config.annotation.*; import java.util.List; /** * 拦截器(可做跨域,token验证等) */ @Configuration public class WebRequestInterceptor implements WebMvcConfigurer { /** * 自定义拦截器() * @param registry */ public void addInterceptors(InterceptorRegistry registry) { // RequestInterceptor为具体拦截逻辑的执行类 实现了HandlerInterceptor接口 // addPathPatterns("/test/**") 意义是访问路径下/test 下所有的访问路径都需要被RequestInterceptor拦截 // excludePathPatterns 这个访问路径/test/exception则不在被RequestInterceptor拦截的范围 // /user/** user下所有路径都包含在内 例:/user/api 、/user/api/zz // /user/* 只有user下一层路径包含在内 例:/user/api(包含) 、/user/api/zz(不包含) // /test/queryUser接口则是token验证后,把token为xx的玩家信息放入Request中,方便接口拿取 registry.addInterceptor(new RequestInterceptor()) .addPathPatterns("/test/**") .addPathPatterns("/test/queryUser") .excludePathPatterns("/test/exception"); } /** * 跨域支持 比如说vue 的axios访问 * @param registry */ public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT") .maxAge(3600 * 24); } /** * 修改访问路径 * @param configurer */ public void configurePathMatch(PathMatchConfigurer configurer) { // 设置为true后,访问路径后加/ 也能正常访问 /user == /user/ // configurer.setUseTrailingSlashMatch(true); } /** * 内容协商机制,主要是方便一个请求路径返回多个数据格式 * @param configurer */ public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { } /** * 处理异步请求的。只能设置两个值,一个超时时间(毫秒,Tomcat下默认是10000毫秒,即10秒),还有一个是AsyncTaskExecutor,异步任务执行器 * @param configurer */ public void configureAsyncSupport(AsyncSupportConfigurer configurer) { // //设置超时时间 // configurer.setDefaultTimeout(1000000); // //设置异步任务执行器 // configurer.setTaskExecutor(new AsyncTaskExecutor() { // @Override // public void execute(Runnable runnable, long l) { // // } // // @Override // public Future submit(Runnable runnable) { // return null; // } // // @Override // public Future submit(Callable callable) { // return null; // } // // @Override // public void execute(Runnable runnable) { // // } // }); } /** * 这个接口可以实现静态文件可以像Servlet一样被访问。 * @param configurer */ public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { } /** * 增加转化器或者格式化器。这边不仅可以把时间转化成你需要时区或者样式。还可以自定义转化器和你数据库做交互,比如传进来userId,经过转化可以拿到user对象 * @param registry */ public void addFormatters(FormatterRegistry registry) { } /** * 添加静态资源--过滤swagger-api (开源的在线API文档) * @param registry */ public void addResourceHandlers(ResourceHandlerRegistry registry) { } public void addViewControllers(ViewControllerRegistry registry) { } public void configureViewResolvers(ViewResolverRegistry registry) { } public void addArgumentResolvers(List resolvers) { } public void addReturnValueHandlers(List handlers) { } /** * 配置消息转换器 * @param converters */ public void configureMessageConverters(List converters) { } public void extendMessageConverters(List converters) { } public void configureHandlerExceptionResolvers(List resolvers) { } public void extendHandlerExceptionResolvers(List resolvers) { } @Nullable public Validator getValidator() { return null; } @Nullable public MessageCodesResolver getMessageCodesResolver() { return null; } }

自定义的拦截器

package com.example.demo.config; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.example.demo.entity.model.ResponseDto; 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.PrintWriter; import java.util.Enumeration; public class RequestInterceptor implements HandlerInterceptor { /** * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller * 返回值: * true表示继续流程(如调用下一个拦截器或处理器); * false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应; */ @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { //将头部信息都转换成map JSONObject map = new JSONObject(); Enumeration headerNames = httpServletRequest.getHeaderNames(); while (headerNames.hasMoreElements()) { String key = headerNames.nextElement(); String value = httpServletRequest.getHeader(key); map.put(key, value); } map.put("token", httpServletRequest.getHeader("AUTH-TOKEN")); //判断从前端传来的头部信息中AUTH-TOKEN的值是否与我们后台定义的token值一致 if("111".equals(map.get("token"))){ //token正确 继续下一步拦截器(如果有) System.out.println("token is right"); //从Spring上下文中拿到UserMapper UserMapper userMapper= ApplicationContextUtil.getBean(UserMapper.class); //获取该token对应的用户信息 User user=userMapper.getUserByToken(String.valueOf(map.get("token"))); //将用户信息放入Request中 httpServletRequest.setAttribute("test",JSON.toJSONString(user)); return true; }else{ //token错误 返回错误response System.out.println("token is error"); PrintWriter writer = null; try { ResponseDto dto=new ResponseDto(); dto.setErrorCode(1002); dto.setMessage("RequestInterceptor"); httpServletResponse.setCharacterEncoding("utf-8"); httpServletResponse.setHeader("Content-Type","application/json"); writer = httpServletResponse.getWriter(); //将返回的错误提示压入流中 writer.write(JSON.toJSONString(dto)); writer.flush(); } catch (Exception e) { } finally { if (null != writer) { writer.close(); } return false; } } } /** * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } /** * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中 */ @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }

接口Controller

package com.example.demo.controller; import com.aliyun.openservices.shade.com.alibaba.fastjson.JSON; import com.example.demo.entity.model.ResponseDto; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController @RequestMapping(value = "/test") public class UserNodeController { @RequestMapping(value = "/index") public String index(){ return "/index"; } /** * 异常报错 * 访问路径:http://127.0.0.1:8090/test/exception * 返回结果: {"errorCode": 1001,"message": "Exception:4","data": null } */ @RequestMapping(value = "/exception") public String getException(){ int[] arr = {1, 2, 3}; System.out.println(arr[4]); ResponseDto dto=new ResponseDto(); dto.setMessage("NoEnterGlobalException"); return JSON.toJSONString(dto); } /** * * 空指针异常报错 * 访问路径:http://127.0.0.1:8090/test/nullPointException * 返回结果:{"errorCode": 1002,"message": "NullPointerException:null","data": null } */ @RequestMapping(value = "/nullPointException") public ResponseDto getNullPointException(){ Object obj = null; obj.toString(); ResponseDto dto=new ResponseDto(); dto.setMessage("NoEnterGlobalNullPointException"); return dto; } /** * 获取全局变量 * 访问路径:http://127.0.0.1:8090/test/getGlobalParm * 返回结果:{"ww":{"ww":"helloQ"}} */ @RequestMapping(value = "/getGlobalParm") public String getGlobalParm(Model model){ Map map = model.asMap(); return JSON.toJSONString(map); } /** * 获取预处理后的数据 * 访问地址及参数:http://127.0.0.1:8090/test/getPreprocessedData?helloA.errorCode=1&helloA.message=a&helloA.data=a&helloB.errorCode=2&helloB.message=b&helloB.data=b * 返回结果:dtoA:{"data":"a","errorCode":1,"message":"a"},dtoB:{"data":"b","errorCode":2,"message":"b"} */ @RequestMapping(value = "/getPreprocessedData") public String getPreprocessedData(@ModelAttribute("helloA")ResponseDto dtoA,@ModelAttribute("helloB")ResponseDto dtoB){ return "dtoA:"+JSON.toJSONString(dtoA)+",dtoB:"+JSON.toJSONString(dtoB); } @GetMapping("/queryUser") public void queryUser(HttpServletRequest request,@RequestParam("token") String token){ //在拦截器中验证token并获取到这个token对应的信息 System.out.println(request.getAttribute("test")); System.out.println(token); } }

全局异常处理类

package com.example.demo.config; import com.example.demo.entity.model.ResponseDto; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class GlobalControllerAdvice { /** * 所有异常处理 * @param request * @param e * @return * @throws Exception */ @ExceptionHandler(value = Exception.class) public @ResponseBody ResponseDto exceptionHandler(HttpServletRequest request,Exception e)throws Exception{ ResponseDto dto=new ResponseDto(); dto.setErrorCode(1001); dto.setMessage("Exception:"+e.getMessage()); return dto; } /** * 空指针异常处理 * @param request * @param e * @return * @throws NullPointerException */ @ExceptionHandler(value = NullPointerException.class) public @ResponseBody ResponseDto exceptionHandler(HttpServletRequest request,NullPointerException e)throws NullPointerException{ ResponseDto dto=new ResponseDto(); dto.setErrorCode(1002); dto.setMessage("NullPointerException:"+e.getMessage()); return dto; } /** * 全局变量 拦截器 * @return */ @ModelAttribute(name="ww") public Map globalData() { HashMap map = new HashMap(); map.put("ww", "helloQ"); return map; } /** * 数据预处理 * @param binder */ @InitBinder("helloA") public void b(WebDataBinder binder) { binder.setFieldDefaultPrefix("helloA."); } @InitBinder("helloB") public void a(WebDataBinder binder) { binder.setFieldDefaultPrefix("helloB."); } }

ApplicationContextUtil(在项目初始化的时候将Spring上下文放入ApplicationContextUtil中,方便后面定时器/拦截器等获取实体类bean)

import org.springframework.context.ApplicationContext; public class ApplicationContextUtil{ private static ApplicationContext applicationContext; //在项目初始化的时候将SpringApplication.run(DemoApplication.class, args)set进去 public static ApplicationContext setApplicationContext(ApplicationContext context){ this.applicationContext=context; } public static object getBean(String beanId){ return applicationContext.getBean(beanId); } public static T getBean(Class clazz){ return applicationContext.getBean(clazz); } } 四、测试结果

如配置类中设置的除了/test/exception ,其他的/test下的路径都应该被我们自定义拦截器拦截

访问路径:http://127.0.0.1:8090/test/exception 结果:在这里插入图片描述

访问路径:http://127.0.0.1:8090/test/nullPointException 输入正确的token的结果: 在这里插入图片描述 输入错误token值的结果: 在这里插入图片描述

http://127.0.0.1:8090/test/queryUser?token=111 验证用户信息能否能在接口中获取 控制台如图: 在这里插入图片描述 数据库如图: 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3