一,编写拦截器文件
package com.tax.config.auth;
import com.alibaba.fastjson.JSON;
import com.tax.util.sign.SignUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
@Component
public class InterceptorConfig implements HandlerInterceptor {
private static Logger logger = LoggerFactory.getLogger(InterceptorConfig.class);
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//获取请求参数
String queryString = httpServletRequest.getQueryString();
logger.info("请求参数:{}", queryString);
//获取请求body
byte[] bodyBytes = StreamUtils.copyToByteArray(httpServletRequest.getInputStream());
String body = new String(bodyBytes, httpServletRequest.getCharacterEncoding());
logger.info("请求体:{}", body);
Map<String, Object> map = JSON.parseObject(body,Map.class);
String signStr = String.valueOf(map.get("sign"));
map.remove("sign");
RSAPublicKey pubKey = SignUtils.loadPublicKeyByStr(SignUtils.publicKey);
String mapSortStr = SignUtils.getSortedContent(map);
// //公钥验证
boolean flagB = SignUtils.verify(mapSortStr,signStr,pubKey);
if(flagB){
return true;
}else {
return false;
}
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
logger.info("兑换服务拦截器-处理请求完成后视图渲染之前的处理操作");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
logger.info("兑换服务拦截器-视图渲染之后的操作");
}
}
二,配置拦截器配置类
package com.tax.config.auth;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
@Value("${server.session.timeout}")
public long times;
//关键,将拦截器作为bean写入配置中
@Bean
public InterceptorConfig myInterceptor(){
return new InterceptorConfig();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//多个拦截器组成一个拦截器链
// addPathPatterns用于添加拦截规则
// excludePathPatterns用户排除拦截
registry.addInterceptor(myInterceptor()).addPathPatterns("/api/**");
super.addInterceptors(registry);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*")
.allowedOrigins("*")
.allowedMethods("PUT", "DELETE", "GET", "POST")
.allowedHeaders("*")
.exposedHeaders("access-control-allow-headers",
"access-control-allow-methods",
"access-control-allow-origin",
"access-control-max-age",
"X-Frame-Options",
"Authorization")
.allowCredentials(false).maxAge(times);
}
}
三,启动类配置使用拦截器,使用 @EnableAutoConfiguration 自动注入配置类,启动加载拦截器
@EnableAutoConfiguration
四,因为 httpServletRequest 中 InputStream 只能获取一次,所以在拦截器中获取输入流之后,接口中就不能获取数据会报400错误,因此需要重写HttpServletRequestWrapper类来支持输入流重复读。
package com.tax.config.auth;
import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
* @author Axin
* @summary 自定义 HttpServletRequestWrapper 来包装输入流
*/
public class AxinHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* 缓存下来的HTTP body
*/
private byte[] body;
public AxinHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = StreamUtils.copyToByteArray(request.getInputStream());
}
/**
* 重新包装输入流
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bodyStream.read();
}
/**
* 下面的方法一般情况下不会被使用,如果你引入了一些需要使用ServletInputStream的外部组件,可以重点关注一下。
* @return
*/
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
@Override
public BufferedReader getReader() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
五定义 DispatcherServlet 来分派 AxinHttpServletRequestWrapper
package com.tax.config.auth;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Axin
* @summary 自定义 DispatcherServlet 来分派 AxinHttpServletRequestWrapper
*/
public class AxinDispatcherServlet extends DispatcherServlet {
/**
* 包装成我们自定义的request
* @param request
* @param response
* @throws Exception
*/
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doDispatch(new AxinHttpServletRequestWrapper(request), response);
}
}
六启动类加载DispatcherServlet 实现分派
package com.tax;
import com.tax.config.auth.AxinDispatcherServlet;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.DispatcherServlet;
@EnableAutoConfiguration
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
@EnableEurekaClient
@EnableZuulProxy
@EnableRedisHttpSession
@MapperScan("com.tax.entity")
@EnableDiscoveryClient
public class TaxServerApplication {
@Bean(name="remoteRestTemplate")
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
@Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new AxinDispatcherServlet();
}
public static void main(String[] agrs){
SpringApplication.run(TaxServerApplication.class,agrs);
}
}
完成