拦截器是依赖于SpringMVC的,SpringMVC框架是高度可配置的,无论其视图技术(如 JSP、FreeMarker、Thymeleaf等)选择何种,SpringMVC的执行流程图大抵是相同的。
执行流程为:
[1] 用户触发某个请求路径,通过浏览器发起一个HTTP Request请求,该请求会被提交至DispatcherServlet前端控制器;
[2] 由DispatcherServlet前端控制器请求一个或者多个HandlerMapping(处理器映射器),并返回一个Handler执行链(HandlerExecutionChain);
[3] DispatcherServlet前端控制器将HandlerMapping处理器映射器返回的执行链中包含的Handler信息发送给HandlerAdapter处理器适配器;
[4] HandlerAdapter处理器适配器根据Handler信息找到并执行相应的Handler处理器(即:项目中的Controller层中的控制器);
[5] Handler处理器执行完毕后,会返回给HandlerAdapter处理器适配器一个ModelAndView对象(SpringMVC的底层对象,封装了Model数据模型和View视图信息);
[6] HandlerAdapter处理器适配器接收到ModelAndView对象后,将其返回给DispatcherServlet前端控制器;
[7] DispatcherServlet前端控制器接收到ModelAndView对象后,回请求ViewResolver视图解析器对视图进行解析;
[8] ViewResolver视图解析器根据View匹配到相应的视图结果,并返回给DispatcherServlet前端控制器;
[9] DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
[10] 视图会被响应给浏览器客户端,并进行渲染。
拦截器主要用于拦截用户请求并作相应的处理,那么其拦截位置必定是在HTTP请求到达DispatcherServlet前端控制器之后、将处理结果响应给浏览器之前。
查看DispatcherServlet前端控制器的继承结构,会看到它其实是HttpServlet的一个子类,其职责如下:
Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception handling facilities.
是http请求处理器/控制器的中央调度器,例如:Web UI控制器或者HTTP远程服务的出口。用于分发web请求到已经注册过的处理器进行处理,并提供方便的映射和异常处理机制。
可以通过实现HandlerInterceptor接口、实现HandlerInterceptor接口自接口、继承HandlerInterceptor接口子类定义一个SpringMVC拦截器。
HandlerInterceptor接口中定义了如下三个default方法,实现子类通过重写相应的方法,在特定的执行流程发生时,执行用户请求的拦截动作,并完成相应的处理操作。
/*Intercept the execution of a handler. Called after HandlerMapping determined an
appropriate handler object, but before HandlerAdapter invokes the handler.
DispatcherServlet processes a handler in an execution chain, consisting of any number
of interceptors, with the handler itself at the end. With this method, each interceptor
can post-process an execution,getting applied in inverse order of the execution chain.
*/
|拦截时机:HandlerMapping处理器映射器匹配到对应的Handler处理器对象,但是还未被HandlerAdapter处理器适配器调用之前发生作用。
|处理执行链中包含的Handler处理器对象。
|作用方式:通过preHandle()这个方法,每一个拦截器对象可以对request代表的HTTP请求对象进行拦截处理,并响应一个自定义HTTP响应消息给浏览器客户端。
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//空方法
return true;
}
/*
Intercept the execution of a handler. Called after HandlerAdapter actually
invoked the handler, but before the DispatcherServlet renders the view.
Can expose additional model objects to the view via the given ModelAndView.
*/
|拦截时机:在HandlerAdapter 处理器适配器调用handler处理器(即Controller控制器)之后,在DispatcherServlet前端控制器借助ViewResolver视图解析器获取到ModelAndView对象后,但是View视图还未被渲染之前。此时:最终的View视图还未被响应给浏览器客户端。
|作用方式:逆序处理执行链对应的请求对象
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {
//空方法
}
/*
Callback after completion of request processing, that is, after rendering
the view. Will be called on any outcome of handler execution, thus allows
for proper resource cleanup.
*/
|拦截时机:在HTTP请求处理完毕,即:View视图被渲染给客户端浏览器之后被调用
|作用方式:在执行链对象内部调用,允许做一些适当的资源清理操作。
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
通过实现HandlerInterceptor接口中的3个default方法,可以自定义拦截器。
在SpringBoot中,HandlerInterceptor 拦截器接口对象交由Spring容器管理,因此需要通过@Component注解进行标注。定义一个拦截器方式如下:
//注解-将拦截器交由Spring容器管理
@Component
public class SelfInterceptor implements HandlerInterceptor {
//methods
/**
* 关于HandlerInterceptor接口
* 实现此接口的子类,可以自定义执行链的处理.
* 当前Web应用可以注册任意数量的自定义拦截器,每一个拦截器都可以用于处理一组特定的请求.
* 这种方式实现的拦截器,无需改动处理器(控制器层)的具体实现.
* Workflow interface that allows for customized handler execution chains.
* Applications can register any number of existing or custom interceptors
* for certain groups of handlers, to add common preprocessing behavior
* without needing to modify each handler implementation.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("接收请求路径时处理:"+request.getRequestURI());
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("响应请求路径前处理:"+request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("响应请求路径后处理:"+request.getRequestURI());
}
}
通过实现HandlerInterceptor接口,配合@Component固然可以自定义一个拦截器,并将其交由Spring容器进行管理,但是并未告诉Spring容器何时调用这个拦截器对象、也没有明确这个拦截器对象用来拦截或者不拦截哪些HTTP请求。
这就需要通过实现WebMvcConfigurer接口,配合@Configuration注解,对拦截器进行注册。
实现WebMvcConfigurer接口的子类,可以基于@EnableWebMvc注解,通过重写接口中的default方法,来修改SpringMVC的默认配置。
这些默认配置例如:
PathMatch路径匹配、AsyncSupport-异步请求支持、
DefaultServletHandling-处理Servlet容器未处理的所有url请求、
addFormatters-Converter和Formatter转换器定制、
addCorsMappings-全局跨域请求处理
configureViewResolvers-视图解析器定制、
getValidator-验证器、
addInterceptors-添加拦截器等等,
每一类配置都对应着一个default方法,因此:根据实际需求,重写对应的default方法即可
package com.xwd.config;
import com.xwd.interceptor.SelfInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
/**
* @ClassName InterceptorConfig-拦截器配置
* @Description: com.xwd.config
* @Auther: xiwd
* @version: 1.0
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
//properties
@Autowired
private SelfInterceptor selfInterceptor;
//methods
/**
* 注册拦截器
* 重写addInterceptors()方法
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
/* public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor)
* 参数类型HandlerInterceptor-将Spring IOC管理的自定义拦截器实例放入即可
* /** 表示拦截所有路径(多重子路径)
* */
InterceptorRegistration interceptorRegistration = registry.addInterceptor(selfInterceptor).addPathPatterns("/**").excludePathPatterns("/student/test");
}
}
package com.xwd.config;
import com.xwd.interceptor.SelfInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
/**
* @ClassName InterceptorConfig-拦截器配置
* @Description: com.xwd.config
* @Auther: xiwd
* @version: 1.0
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
//methods
/**
* 跨域访问配置
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600)
.allowedHeaders("*");
}
}
HandlerInterceptor接口中的3个方法如何产生作用?
先看一下HandlerExecutionChain执行链类。
Handler execution chain, consisting of handler object and any handler interceptors.Returned by HandlerMapping’s getHandler method.
HandlerExecutionChain执行链对象与拦截器关系如下:
HandlerExecutionChain执行链对象是由一个Handler处理器对象和多个Interceptor拦截器对象组成的。
此外,HandlerInterceptor拦截器的接口方法是通过HandlerExecutionChain执行链对象内部的三个成员方法所调用的,这3个成员方法分别如下:
[1] boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)
[2] void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
[3] void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)。
在这三个方法内部,通过遍历HandlerExecutionChain执行链对象内部持有的多个拦截器,分别对preHandle、postHandle、afterCompletion方法进行调用。
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
那么,HandlerExecutionChain执行链对象是如何从HandlerMapping处理器映射器返回到DispatcherServlet前端控制器的呢?
在解释之前,先看一下DispatcherServlet前端控制器是如何分发HTTP请求的。
SpringMVC的前端控制器DispatcherServlet类中包含一个doDispatch()方法,该方法可以负责HTTP请求到Handler处理器的实际调度,所有的HTTP方法都会被此方法处理,并由HandlerAdapters 处理器适配器或者handler处理器自己决定可接收的HTTP请求。
代码如下:当前仅需要关注如下几点,
[1] 获取HandlerExecutionChain 执行链对象的方法,DispatcherServlet的doDispatch()方法中,会调用 另一个成员方法getHandler(processedRequest)方法,其中:processedRequest就是HttpServletRequest 对象;
[2] 成员方法getHandler()方法内部通过一个for循环,来遍历内部持有的HandlerMapping列表,调用HandlerMapping处理器映射器的getHandler()方法获取一个HandlerExecutionChain执行链对象,并将其返回;
[3] HandlerMapping处理器映射器的的getHandler()方法作用: Return a handler and any interceptors for this request.将当前HTTP请求封装过来的HttpServletRequest对象作为参数接收,找到它对应的处理器或者拦截器对象,将其返回。
doDispatch()方法大致的执行流程已给出注释。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//HttpServletRequest对象
HttpServletRequest processedRequest = request;
//执行链对象
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//调用getHandler()方法,内部借助HandlerMappings处理器映射器对象获取执行链对象
mappedHandler = getHandler(processedRequest);
//如果执行链为空-调用noHandlerFound()
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// mappedHandler.getHandler()-获取Handler处理器对象
// 将Handler处理器对象交由HandlerAdapter处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
//获取HTTP请求方式,例如:GET, POST, or PUT等
String method = request.getMethod();
//根据请求方式来做进一步处理
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
//为当前的request, response对——创建ServletWebRequest对象
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//判断执行链对象是否需要处理下一个Handler或者Interceptor
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//通过HandlerAdapter 处理器适配器调用handle()方法,实际调用handler处理器(controller控制器),对request请求进行处理,并由Handler处理器返回一个ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//将ModelAndView对象应用到当前request对象上
applyDefaultViewName(processedRequest, mv);
//通过执行链调用applyPostHandle,内部调用HandlerInterceptor接口的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
/**
* Return the HandlerExecutionChain for this request.
* Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
DispatcherServlet前端控制器接收到HandlerMapping处理器映射器返回的一个执行链HandlerExecutionChain对象(该对象是在前端控制器的doPost()->getHandler()方法中,通过遍历HandlerMapping列表,由列表元素调用getHandler()方法返回),HandlerExecutionChain包含多个Handler处理器对象和一组拦截器interceptor对象。
DispatcherServlet在获取到执行链对象之后,就可以通过执行链中的三个成员方法:applyPreHandle、applyPostHandle、triggerAfterCompletion,对拦截器对象(即:HandlerInterceptor接口实例)被重写的接口方法发起调用,对HTTP请求进行拦截操作。而接口方法被调用的时机,在2.2中已经介绍过。
基于以上认知,可以知道:HandlerInterceptor拦截器接口隶属于SpringMVC的一部分,无论是在基于Spring,还是Spring Boot搭建的web项目中,都可以进行配置使用。
其使用流程如下:
[1] 通过实现HandlerInterceptor接口定义拦截器;
[2] 将HandlerInterceptor拦截器交由Spring容器管理;
[3] 注册HandlerInterceptor拦截器,明确拦截器可以拦截哪一类HTTP请求。
以Spring+Spring MVC项目为例,进行拦截器实现。
在前后端分离的项目中,例如前端通过Vue技术栈+Axios开发,而Axios默认是无状态的,后端无法通过HttpSession记录用户登陆状态,从而判断用户是否可以执行某些请求操作。此时,就需要通过使用一些特殊方法记录用户登陆状态,而jwt就是一种实现方式。
jwt官方地址:点击此处。
JWT,全称为:JSON Web Token,基于JSON对象,定义了一种轻量级的、自包含(self-contained)方式的安全信息传输方式。通过数字签名,这种JSON信息可以进行验证,从而用于实现权限控制(Authorization)或者信息交换(Information Exchange)。
JSON Web Token由三部分组成:header-头部、payload-载荷、Signature-签名,各部分之间通过.点进行分隔,例如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDg3NTEyNDcsImVtYWlsIjoiWHdkOTQ5MjY0QDE2My5jb20ifQ.F_zCAasNiBdbVaVg3eKo3I5NIFTzh_mErDeJOhQhP5o
更多介绍可以查看官网介绍。
基于token进行接口访问拦截,需要通过定义拦截器,利用jwt(JSON Web Token)技术,基于token进行用户后端接口访问权限的认证。
对于没有携带token值的HTTP请求,默认拒绝该请求;对于携带token值的HTTP请求,接受并进行相应的处理操作。
先在pom.xml中引入jwt依赖。
<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.18.3version>
dependency>
先在pom.xml中引入jwt依赖。
package com.xwd.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName JWTUtil
* @Description: com.xwd.util
* @Auther: xiwd
* @version: 1.0
*/
public class JWTUtil {
//properties
private static final String SIGN="eyJwc3dkIjoiWQiOiJyb290In0!@ds";
//methods
/**
* 根据传入信息生成Token
* header.payload.Signature
* @param mapinfo 携带用户信息的map集合
*/
public static String genereteToken(Map<String,String> mapinfo){
Calendar instance = Calendar.getInstance();
//有效期为3小时
instance.add(Calendar.MINUTE,60*3);
//map用户存储claim——声明的信息
Map<String,Object> map=new HashMap<>();
//生成token
JWTCreator.Builder builder = JWT.create();
//添加payload
mapinfo.forEach((k,v)->{
builder.withClaim(k,v);
});
//指定令牌过期时间
builder.withExpiresAt(instance.getTime());
//指定算法-生成token
String token = builder.sign(Algorithm.HMAC256(SIGN));
return token;
}
/**
* 验证token的合法性
* @param token token令牌值
* throw 抛出异常-表示验证失败
*/
public synchronized static void decodeToken(String token){
JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
}
/**
* 获取token信息的方法
* @param token token令牌值
* @return DecodedJWT对象
* throw 抛出异常-表示验证失败
*/
public synchronized static DecodedJWT getTokenInfo(String token){
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
return decodedJWT;
}
}
在用户登录时,自动生成一个token值信息,将其返回给前端,保存到localStorage中,之后每次向后端发起请求时,将其添加到请求头中,以便于后端验证。
@RequestMapping(value = "/POST/login",method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> login(@RequestParam(value = "uname")String username,
@RequestParam(value = "pswd")String password){
System.out.println("login");
Map<String,Object> resMap=new HashMap<>();
//判断用户名和密码是否为空
if (StrUtil.isEmpty(username)||StrUtil.isEmpty(password)){
resMap.put("state",0);
resMap.put("msg","登陆失败-信息填写不完整");
return resMap;
}
//查询符合条件的用户是否存在
User user = userService.selectUser(username, password);
if(user==null){
resMap.put("state",-1);
resMap.put("msg","登陆失败-账户或密码错误");
return resMap;
}
//判断当前账户是否可用
if (user.getState()!=0){
//登录成功,创建Token值
HashMap<String, String> map = new HashMap<>();
map.put("email",username);
//调用jwt工具类,生成token
String token = JWTUtil.genereteToken(map);
resMap.put("state",1);
resMap.put("msg","登陆成功");
resMap.put("token",token);
resMap.put("user",username);
return resMap;
}else {
//state==0,表示[账户禁用]
resMap.put("state",-2);
resMap.put("msg","登陆失败,账户不存在被禁用!");
return resMap;
}
}
通过实现HandlerInterceptor 接口,自定义拦截器。
package com.xwd.interceptor;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xwd.util.JWTUtil;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerExecutionChain;
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.HashMap;
import java.util.Map;
/**
* @ClassName JWTInterceptor
* @Description: com.xwd.interceptor
* @Auther: xiwd
* @version: 1.0
*/
public class JWTInterceptor implements HandlerInterceptor {
//methods
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取HttpServletRequest请求头中携带的token信息
String token = request.getHeader("token");
Map<String,Object> infoMap = new HashMap<>();
try{
//token验证
DecodedJWT tokenInfo = JWTUtil.getTokenInfo(token);
//添加返回信息
infoMap.put("state",true);
infoMap.put("msg","验证成功");
return true;
}catch (SignatureVerificationException e){
e.printStackTrace();
infoMap.put("msg","无效签名");
infoMap.put("state",false);
}catch (TokenExpiredException e){
infoMap.put("msg","token已过期");
infoMap.put("state",false);
}catch (AlgorithmMismatchException e){
infoMap.put("msg","算法不一致");
infoMap.put("state",false);
}catch (Exception e){
infoMap.put("msg","无效签名");
infoMap.put("state",false);
}
//将Map转为JSON返回给前端
ObjectMapper objectMapper = new ObjectMapper();
String mapInfoJson = objectMapper.writeValueAsString(infoMap);
response.setContentType("application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.write(mapInfoJson);
return false;
}
}
在springMVC-context.xml配置文件中配置拦截器。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/user/POST/register"/>
<mvc:exclude-mapping path="/user/POST/login"/>
<mvc:exclude-mapping path="/sender/GET/email"/>
<mvc:exclude-mapping path="/**/*.js"/>
<mvc:exclude-mapping path="/upload/**"/>
<bean class="com.xwd.interceptor.JWTInterceptor">bean>
mvc:interceptor>
mvc:interceptors>
如果为Vue+Axios,可以通过Axios配置拦截器,为每次的HTTP请求头加上本地存储的token信息,交由后端的HandlerInterceptor拦截器实现子类JWTInterceptor 进行token校验。
Axios拦截器介绍:官网地址,主要是在每一个请求或响应被 then 或 catch 处理前拦截它们。 示例如下:
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
自定义前端拦截器,可以在main.js文件中添加如下代码:
import axios from 'axios'
// Vue.prototype.$axios = axios
axios.defaults.baseURL = 'http://localhost:8010/stasys_v3/'
//axios-添加请求拦截器interpetor
axios.interceptors.request.use(
function(config) {
//在发送请求之前,从localStorage获取token
var token = localStorage.getItem('token')
//判断token是否为空
if (token && token != '') {
//不为空则添加token信息到请求头
config.headers['token'] = token
}
return config
},
function(err) {
//错误处理
return Promise.reject(err)
}
)
//挂载axios
Vue.prototype.$axios = axios
也可以基于token为router路由配置导航守卫,在页面跳转时进行安全验证,这个看自己的需求。
参见2.2.3部分的举例即为SpringBoot中拦截器的简单实现。