需求
实现外部接口访问进行签名验证
计划
1.自定义一个注解类
2.定义一个POST请求接口,并用注解标识
3.自定义一个切面和一个过滤器
自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface CallbackHandler {
}
post接口
这里需要注意@RequestBody 只能搭配post请求
@CallbackHandler
@PostMapping("/dd")
public Result commonOrderRefund(
@RequestBody Object request
) {
//业务处理
return ResultModel.SUCCESS;
}
编写切面
错误的写法
对于servketrequest来说,InputStream只能读取一次
InputStream里面有做指针和同步处理,一旦指针到了末尾是不会回来的。那么我们怎么拷贝request body里面的数据呢,当然我们得找一种可以复制的存储方式了,比如String,可以先把request 的inputStream转成String,然后又把String转成byte[] 存回去就是了,String对象我们可以无限使用。
//用一个final request接收,再去读取
final HttpServletRequest httpServletRequest = new ContentCachingRequestWrapper(request);
String requestBody = ByteSource.wrap(ByteStreams.toByteArray(httpServletRequest.getInputStream())).asCharSource(StandardCharsets.UTF_8).read();
@Slf4j
@RequiredArgsConstructor
public class CallbackInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (!(handler instanceof HandlerMethod)) {
return super.preHandle(request, response, handler);
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
CallbackHandler callbackHandler = Optional
.ofNullable(handlerMethod.getMethodAnnotation(CallbackHandler.class))
.orElse(handlerMethod.getBeanType().getAnnotation(CallbackHandler.class));
if (callbackHandler == null) {
return super.preHandle(request, response, handler);
}
//boolean ok = 签名验证逻辑 如果直接获取 request.get
//这样就可以轻松取到request的body也不会破坏request
String requestBody = ((RequestWrapper) request).getBody()
if (ok) {
log.info("恭喜签名成功,快过去干活吧");
return super.preHandle(request, response, handler);
} else {
this.response(response);
return false;
}
}
}
自定义一个Wrapper
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder("");
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
log.error("关闭流失败",ex);
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public boolean isFinished() {
return false;
}
public boolean isReady() {
return false;
}
public void setReadListener(ReadListener readListener) {
}
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
定义一个过滤器
public class HttpRequestWrapperFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
boolean isMultipart = StrUtil.startWith(request.getContentType(), "multipart");
filterChain.doFilter(isMultipart
? request
: new RequestWrapper(request),
response);
}
}
写一个配置类
@Configuration
@EnableWebMvc
@RequiredArgsConstructor
public class SignInterceptorConfiguration implements WebMvcConfigurer {
private final SupplierMapper supplierMapper;
@Override
public void addInterceptors(InterceptorRegistry registry) {
CallbackInterceptor signInterceptor = new CallbackInterceptor(supplierMapper);
registry.addInterceptor(signInterceptor).addPathPatterns("/**/dd/**");
}
@Bean
public FilterRegistrationBean httpRequestWrapperFilter() {
HttpRequestWrapperFilter httpRequestWrapperFilter = new HttpRequestWrapperFilter();
FilterRegistrationBean<HttpRequestWrapperFilter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new HttpRequestWrapperFilter());
filterFilterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
filterFilterRegistrationBean.setName("request_wrapper");
return filterFilterRegistrationBean;
}
}
以上就是我的代码总结,欢迎交流