Spring Boot添加签名拦截器
1、重写getInputStream()和getReader() 获取请求正文
public class RequestWrapper extends HttpServletRequestWrapper {
private byte[] requestBody =null;
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
}
/**
* 获取请求体
* @param request
* @return
*/
public String getBodyString(final ServletRequest request) {
try {
return inputStream2String(request.getInputStream());
} catch (IOException e) {
log.error("", e);
throw new RuntimeException(e);
}
}
/**
* 获取请求体
* @return
*/
public String getBodyString() {
final InputStream inputStream = new ByteArrayInputStream(requestBody);
return inputStream2String(inputStream);
}
/**
* 获取请求体
* @param inputStream
* @return
*/
private String inputStream2String(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
log.error("异常:", e);
throw new RuntimeException(e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
log.error("", e);
}
}
}
return sb.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
2、替换原生HttpServletRequest
@Slf4j
@WebFilter(urlPatterns = "/*")
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("过滤器初始化...");
}
@Override
public void doFilter(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("过滤器销毁...");
}
}
3、添加签名拦截器
@Slf4j
@Component
public class SignInterceptor implements HandlerInterceptor {
/**
* 前置处理器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String strParam = new RequestWrapper(request).getBodyString();
Map<String, Object> paramsMap = convertMap(strParam);
if (paramsMap.get("signData") != null && StringUtils.isBlank(paramsMap.get("signData").toString())) {
//重置response
response.reset();
//设置编码格式
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
JSONObject resultObj = new JSONObject();
resultObj.put("success",false);
resultObj.put("message","未传入签名数据,验签失败!");
resultObj.put("code","-1");
PrintWriter printWriter = response.getWriter();
printWriter.write(resultObj.toJSONString());
return false;
}
if (!verifySign(strParam)) {
//重置response
response.reset();
//设置编码格式
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
JSONObject resultObj = new JSONObject();
resultObj.put("success",false);
resultObj.put("message","传入签名数据不正确,验签失败!");
resultObj.put("code","-1");
PrintWriter printWriter = response.getWriter();
printWriter.write(resultObj.toJSONString());
return false;
}
return true;
}
/**
* JSON字符串转MAP
*/
public Map<String, Object> convertMap(String str) {
JSONObject jsonParam = JSONObject.parseObject(str);
return new HashMap<>(jsonParam);
}
/**
* @Description 验证签名是否一致
* @date 2023/11/28 14:43
* @param params
* @return boolean
*/
public boolean verifySign(String params){
MedinsCommonRequest medinsCommonRequest = JSONObject.parseObject(params, MedinsCommonRequest.class);
String content = SM2Utils.spliceData(medinsCommonRequest);
return SM2Utils.verify(SM2Utils.PUBLIC_KEY, content, medinsCommonRequest.getSignData());
}
4、注册拦截器,声明要拦截的url
@Slf4j
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public HandlerInterceptor getSignInterceptor() {
return new SignInterceptor();
}
/**
* @Description 注册拦截器,声明要拦截的url
* @author taoh
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 签名拦截
InterceptorRegistration signInterceptor = registry.addInterceptor(getSignInterceptor());
signInterceptor.addPathPatterns("/xxxx/**");
}
}
5、最后记得在启动类上加@ServletComponentScan注解 ,SpringBoot在启动时会扫描并注册所有带有@WebServlet(控制器)、@WebFilter(过滤器)、@WebListener(监听器)注解的类