java实现md5签名实现对外调用接口

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();
	}

你可能感兴趣的:(java,java,servlet,开发语言)