1、编写接口过滤器
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.*;
/**
* @author : nyl
* create at: 2022/11/7 10:36 下午
* @description:
*/
@Slf4j
@Order(1)
@WebFilter
@Component
public class ApiReqFilter implements Filter {
/**
* 签名验证时间(TIMES =分钟 * 秒 * 毫秒)
* 当前设置为:5分钟有效期
*/
protected static final Integer TIMES = 5 * 60 * 1000;
//需要验签的请求地址
public List<String> ignoreUrl
= Arrays.asList(
"/wash/wsorder/getOrderList",
"/qm-currency/refundlog/getRefundList",
"/wash/amountwater/getAmountWaterList");
@Override
public void init(FilterConfig filterConfig) {
System.out.println("ApiReqFilter---->init()");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
Map<String, Object> map = new HashMap<>();
//获取请求URI
String requestURI = request.getRequestURI();
System.out.println(requestURI+"---");
if (!ignoreUrl.contains(requestURI)) {
// 放行
chain.doFilter(request, response);
} else {
// 判断请求方式
String method = request.getMethod();
if ("POST".equals(method)) {
// 获取请求Body参数,需要使用 BodyReaderHttpServletRequestWrapper进行处理
// 否则会出现异常:I/O error while reading input message; nested exception is java.io.IOException: Stream closed
// 原因就是在拦截器已经读取了请求体中的内容,这时候Request请求的流中已经没有了数据
// 解决流只能读取一次的问题:先读取流,然后在将流重新写进去就行了
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
String body = HttpHelper.getBodyString(requestWrapper);
String bodyString = URLDecoder.decode(body, "utf-8");
if (StrUtil.isEmpty(bodyString)) {
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.setCharacterEncoding("utf-8");
map.put("code", 400);
map.put("msg", "请求参数不能为空");
writer.print(JSONObject.toJSONString(map));
writer.close();
return;
}
// 解析参数转JSON格式
// bodyString = "{" + bodyString.replace("&", "',").replace("=", ":'") + "'}";
JSONObject jsonObject = JSONObject.parseObject(bodyString);
// 验签
boolean validation = validation(jsonObject, response);
if (!validation) {
return;
}
// 放行
chain.doFilter(request, response);
}
if ("GET".equals(method)) {
// 获取请求参数
Map<String, String> allRequestParam = getAllRequestParam(request);
Set<Map.Entry<String, String>> entries = allRequestParam.entrySet();
// 参数转JSON格式
JSONObject jsonObject = new JSONObject();
entries.forEach(key -> {
jsonObject.put(key.getKey(), key.getValue());
});
// 验签
boolean validation = validation(jsonObject, response);
if (!validation) {
return;
}
// 放行
chain.doFilter(request, response);
}
}
}
/**
* 验签
*
* @param body 请求参数
* @param response
* @return
* @throws IOException
*/
private boolean validation(JSONObject body, HttpServletResponse response) throws IOException {
// 拿出请求签名
String sign = body.getString("sign");
Assert.notBlank(sign, "sign is required");
Assert.notNull(body.getLong("dateTime"), "dataTime is required");
body.remove("sign");
// 根据APPID查询的密钥进行重签
String sign1 = getSign(body);
Map<String, Object> map = new HashMap<>();
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.setCharacterEncoding("utf-8");
// 校验签名
if (!sign.equals(sign1)) {
map.put("code", 10000);
map.put("msg", "签名错误");
writer.print(JSONObject.toJSONString(map));
return false;
}
// 校验签名是否失效
long thisTime = System.currentTimeMillis() - body.getLong("dateTime");
if (thisTime > TIMES) {// 比对时间是否失效
map.put("code", 20000);
map.put("msg", "签名失效");
writer.print(JSONObject.toJSONString(map));
return false;
}
return true;
}
/**
* 计算签名
*
* @param params
* @return
*/
public static String getSign(JSONObject params) {
// 从缓存中获取密钥
String key = "自己定义key";
// 参数进行字典排序
String sortStr = getFormatParams(params);
// 将密钥key拼接在字典排序后的参数字符串中,得到待签名字符串。
sortStr += "key=" + key;
// 使用md5算法加密待加密字符串并转为大写即为sign
// String sign = SecureUtil.md5(sortStr).toUpperCase();
String sign = DigestUtils.md5DigestAsHex(sortStr.getBytes()).toUpperCase();
return sign;
}
/**
* 参数字典排序
*
* @param params
* @return
*/
public static String getFormatParams(Map<String, Object> params) {
List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
public int compare(Map.Entry<String, Object> arg0, Map.Entry<String, Object> arg1) {
return (arg0.getKey()).compareTo(arg1.getKey());
}
});
String ret = "";
for (Map.Entry<String, Object> entry : infoIds) {
ret += entry.getKey();
ret += "=";
ret += entry.getValue();
ret += "&";
}
return ret;
}
/**
* 获取客户端GET请求中所有的请求参数
*
* @param request
* @return
*/
private Map<String, String> getAllRequestParam(final HttpServletRequest request) {
Map<String, String> res = new HashMap<String, String>();
Enumeration<?> temp = request.getParameterNames();
if (null != temp) {
while (temp.hasMoreElements()) {
String en = (String) temp.nextElement();
String value = request.getParameter(en);
res.put(en, value);
//如果字段的值为空,判断若值为空,则删除这个字段>
if (null == res.get(en) || "".equals(res.get(en))) {
res.remove(en);
}
}
}
return res;
}
}
2、工具类
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Enumeration;
/**
* @author : nyl
* create at: 2022/11/7 10:39 下午
* @description:
*/
public class BodyReaderHttpServletRequestWrapper extends
HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
Enumeration e = request.getHeaderNames() ;
while(e.hasMoreElements()){
String name = (String) e.nextElement();
String value = request.getHeader(name);
System.out.println(name+" = "+value);
}
body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
};
}
@Override
public String getHeader(String name) {
return super.getHeader(name);
}
@Override
public Enumeration<String> getHeaderNames() {
return super.getHeaderNames();
}
@Override
public Enumeration<String> getHeaders(String name) {
return super.getHeaders(name);
}
}
import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
/**
* @author : nyl
* create at: 2022/11/7 10:40 下午
* @description:
*/
public class HttpHelper {
public static String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("sb = " + sb);
return sb.toString();
}
}
3、编写测试类
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import org.springblade.common.apiSign.ApiReqFilter;
import org.springframework.boot.test.context.SpringBootTest;
import org.testng.annotations.Test;
import java.util.*;
/**
* @author : nyl
* create at: 2022/11/7 10:41 下午
* @description:
*/
@SpringBootTest
public class TestHttpReq {
public static String secretKey = "自己定义的key";
@Test
public void testPost() {
JSONObject data = new JSONObject();
data.put("name", "xxx");
data.put("age", "11");
data.put("app_id", "1234");
long dateTime = new Date().getTime();
data.put("date_time", "1656926899731");
String sign = ApiReqFilter.getSign(data);
//修改密钥为数据加密后加密串
data.put("sign", sign);
HttpResponse response = HttpRequest.post("localhost:8088/wash/wsorder/list").form(data).contentType("application/json").execute();
Object jsonObject = JSONObject.parse(response.body().trim());
System.out.println("jsonObject = " + jsonObject);
}
@Test
public void testGet() {
String url = "localhost:8088/wash/amountwater/getAmountWaterList";
long dateTime = new Date().getTime();
//传入参数
JSONObject data = new JSONObject();
data.put("dateTime", dateTime);
data.put("current", 1);
data.put("size", 1);
data.put("tenantId", "183571");
data.put("startTime", "2020-02-09");
data.put("endTime", "2023-02-09");
String sign = ApiReqFilter.getSign(data);
System.out.println(sign+"----"+data);
url = url + "?startTime=2020-02-09&endTime=2023-02-09¤t=1&size=1&tenantId=183571&dateTime=" + dateTime + "&sign=" + sign;
HttpResponse response = HttpRequest.get(url).execute();
System.out.println(url);
System.out.println("response.body() = " + response.body().trim());
}
}
4、编写调用接口 (接口自己实现即可)
@GetMapping("/getOrderList")
@ApiOperation(value = "分页查询订单列表", notes = "传入wsOrder")
public void listInfo(QOrderDTO qOrderDTO, Query query, HttpServletResponse httpServletResponse) throws IOException {
JSONObject json = new JSONObject();
try {
IPage<WsOrderVO> data = wsOrderService.listPageVo(Condition.getPage(query), BeanUtil.copyProperties(qOrderDTO,QueryGoodsOrderDTO.class));
json.put("code", 200);
json.put("msg", "success");
json.put("data", data);
} catch (Exception e) {
e.printStackTrace();
json.put("code", 500);
json.put("msg", "调用失败,请稍后重试!");
json.put("data", null);
}
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setContentType("application/json; charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write(json.toString());
writer.flush();
writer.close();
}