Enlace original: http://www.360doc.com/document/19/0106/20/39911641_807065847.shtml
Hay una descripción general de la lógica empresarial de lectura y verificación repetibles en el enlace original.
Pasos de implementación de código
primer paso
编写 RequestWrapper 类 extiende HttpServletRequestWrapper
package com.xihongshi.common.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
/**
* @author mgq
* @since 2021-03-30 9:59
*/
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
/**
* 存储body数据
*/
private final byte[] body;
public RequestWrapper(final HttpServletRequest request) {
super(request);
// 将body数据存储起来
String bodyStr=getBodyString(request);
// 初始化body
body = bodyStr.getBytes(Charset.defaultCharset());
}
public String getBodyString(ServletRequest request) {
try {
return inputStream2String(request.getInputStream());
} catch (IOException e) {
log.error("",e);
throw new RuntimeException(e);
}
}
public String getBodyString() {
final InputStream byteArrayInputStream = new ByteArrayInputStream(body);
return inputStream2String(byteArrayInputStream);
}
private String inputStream2String(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
BufferedReader reder = null;
try {
reder=new BufferedReader(new InputStreamReader(inputStream,Charset.defaultCharset()));
String line;
while ((line=reder.readLine())!=null){
sb.append(line);
}
} catch (Exception e) {
log.error("",e);
throw new RuntimeException(e);
}finally {
if (reder!=null) {
try {
reder.close();
} catch (IOException e) {
log.error("",e);
}
}
}
return sb.toString();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(final ReadListener readListener) {
}
@Override
public int read() throws IOException {
return inputStream.read();
}
};
}
}
Segundo paso
Escribe la clase ReplaceStreamFilter, implementa Filter
package com.xihongshi.common.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author mgq
* @since 2021-03-30 10:20
*/
@Slf4j
public class ReplaceStreamFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("StreamFilter初始化");
}
@Override
public void doFilter(final ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);
chain.doFilter(requestWrapper,response);
}
@Override
public void destroy() {
log.info("StreamFilter销毁");
}
}
tercer paso
Escriba la clase JWTInterceptor, implementa HandlerInterceptor que se usa para probar para obtener datos del cuerpo de la solicitud y para verificar si la interfaz posterior puede recibir los datos en @requestBody
package com.xihongshi.client.interceptor;
import com.auth0.jwt.JWT;
import com.xihongshi.common.constants.RedisConstants;
import com.xihongshi.common.errcode.BizErrorCodeEnum;
import com.xihongshi.common.exception.BizException;
import com.xihongshi.common.exception.InvalidSessionException;
import com.xihongshi.common.filter.RepeatableRequestWrapper;
import com.xihongshi.common.filter.RequestWrapper;
import com.xihongshi.utils.JwtUtils;
import com.xihongshi.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.SignUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
/**
*
* @author: mengshaoshuai
* @date 2021年3月12日 下午1:51:20
*/
@Slf4j
public class JWTInterceptor implements HandlerInterceptor {
@Value("${client.auth.test.enabled:false}")
private boolean authTestEnabled = false;
@Value("${client.auth.test.accountId:}")
private Integer authTestAccountId;
@Autowired
JwtUtils jwtUtils;
@Autowired
RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String token = request.getHeader("token");
String sb = new RequestWrapper(request).getBodyString();
System.out.println(sb);
try {
jwtUtils.verify(token);
} catch (Exception e) {
if(authTestEnabled) {
//test
request.setAttribute("unionId", authTestAccountId+"");
request.setAttribute("accountId", authTestAccountId+"");
}else{
throw new InvalidSessionException(BizErrorCodeEnum.JWT_TOKEN_ERROR);
}
return true;
}
String id = JWT.decode(token).getAudience().get(0);
String tknow = (String)redisUtil.get(RedisConstants.JWT_KEY_ACCOUNT+id);
if(tknow==null || !tknow.equals(token)) {
throw new BizException(BizErrorCodeEnum.JWT_TOKEN_EXPIRE);
}
String mobile = JWT.decode(token).getClaim("mobile").asString();
request.setAttribute("accountId", id);
request.setAttribute("unionId", mobile);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
clearMdc();
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
clearMdc();
}
/**
* 清理日志上下文
*/
protected void clearMdc() {
try {
MDC.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
}
el cuarto paso
Clase de configuración del filtro
Nota: Los pasos cuarto y quinto no tienen que configurarse, o de lo contrario los pasos 1 y 2 no surten efecto
package com.xihongshi.client.interceptor;
import com.xihongshi.common.filter.RepeatableReadFilter;
//import com.xihongshi.common.filter.ReplaceStreamFilter;
import com.xihongshi.common.filter.ReplaceStreamFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
/**
* 过滤配置类
* @author mgq
* @since 2021-03-30 10:52
*/
@Configuration
public class FilterConfig {
/**
* 注册过滤器
* @return
*/
@Bean
public FilterRegistrationBean someFilterRegistration(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(replaceStreamFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("streamFilter");
return filterRegistrationBean;
}
/**
* 实例化StreamFilter
* @return
*/
@Bean(name="replaceStreamFilter")
public Filter replaceStreamFilter(){
return new ReplaceStreamFilter();
}
}
el quinto paso
Configuración del interceptor
package com.xihongshi.client.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置
* @author mgq
* @since 2021-03-30 11:12
*/
@Slf4j
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public JWTInterceptor getJWTInterceptor(){
return new JWTInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getJWTInterceptor())
.addPathPatterns("/**");
}
}
Sexto paso
Siéntase libre de escribir una interfaz de controlador, el parámetro de llamada en la interfaz es el objeto json recibido por @requestbody