接口防篡改

思路:appId,appKey(appSecret)(网络中不传输),提供方将这两个参数下发给使用方。

httpServletRequest.getParameterNames():获取所有参数的名字
@Data
public class SignDTO {

	private String appId;

	private String name;

	private  String sign;

}
@RestController
@RequestMapping("/api-safe")
public class ApiSafeController {

	@GetMapping("/hello")
	public String hello(){
		return  "hello api safe";
	}

	/**
	 * 测试 get 方法 参数防篡改
	 * @return
	 */
	@RequestMapping("/get-test")
	public String getTest(String appId, String name , String sign , long timestamp , HttpServletRequest httpServletRequest){

		// 为了排序
		HashMap<String,String> map= new HashMap<>();

		// 参数写死
//		map.put("appId",appId);
//		map.put("name",name);
//		map.put("timestamp",timestamp);

		// 获取get中的参数
		Enumeration<String> parameterNames = httpServletRequest.getParameterNames();
		while (parameterNames.hasMoreElements()){
			//获取 name
			String parametename = parameterNames.nextElement();

			// 获取值
			String parameterValue = httpServletRequest.getParameter(parametename);
			map.put(parametename,parameterValue);
		}

		// 让接口在有效期内访问
//		long time = System.currentTimeMillis() - timestamp;
//		if (time > 1000 * 30){
//			return "接口过期了";
//		}

		String s = CheckUtils.generatorSign(map);
		if (s.equals(sign)){
			return "校验通过";
		}else {
			return "校验 不通过";
		}

	}


	@PostMapping("/post-test")
	public String postTest(@RequestBody SignDTO signDTO){
		System.out.println("进入controller方法");

		JSONObject obj = JSONUtil.parseObj(signDTO);
		System.out.println("controller参数:"+obj);

		return "controller";

	}
}
public class CheckUtils {

	/**
	* app secret和 appId,一一对应
	 */
	public static String appSecret = "aaa";

	// 校验 签名
	public static boolean checkSign(Map<String,String> map){
		String sign = (String) map.get("sign");
		map.remove("sign");
		// 生成sign
		String s = CheckUtils.generatorSign(map);
		if (s.equals(sign)){
			return true;
		}else {
			return false;
		}

	}

	// 根据map生成签名
	public static String generatorSign(Map<String,String> map){
		map.remove("sign");
		// 排序:
		Map<String, String> stringObjectMap = sortMapByKey(map);
		// 转格式:   name=张三&age=10,:  name,张三,age,10
		Set<Map.Entry<String, String>> entries = stringObjectMap.entrySet();
		StringBuilder sb = new StringBuilder();
		for (Map.Entry<String,String> e : entries){
			sb.append(e.getKey()+","+e.getValue()).append("#");
		}


		// 组装secret  在参数的后面 添加 secret
		sb.append("secret").append(appSecret);
		// 生成签名
		return MD5Util.md5(sb.toString());
		// sha256生成 签名
//		return Sha256Utils.getSHA256(sb.toString());
	}

	public static Map<String,String> sortMapByKey(Map<String,String> map){
		// 判断一下map是否为空,自己写

		Map<String,String> sortMap = new TreeMap<>(new MyMapComparator());

		sortMap.putAll(map);

		return  sortMap;

	}

	static class MyMapComparator implements Comparator<String>{
		@Override
		public int compare(String o1, String o2) {
			return o1.compareTo(o2);
		}
	}

	public static void main(String[] args) {
		HashMap<String,String> map = new HashMap<>();
		map.put("appId","1");
		map.put("name","2");
		map.put("urlParam","3");

		Map<String, String> stringObjectMap = sortMapByKey(map);
		System.out.println(stringObjectMap);



		String s = generatorSign(map);
		// 74f0c8c14fd2869121c910601e9ea859
		System.out.println(s);
	}

}
public class Sha256Utils {

	/**
	 * 利用java原生的类实现SHA256加密
	 *
	 * @param str 加密后的报文
	 * @return
	 */
	public static String getSHA256(String str) {
		MessageDigest messageDigest;
		String encodestr = "";
		try {
			messageDigest = MessageDigest.getInstance("SHA-256");
			messageDigest.update(str.getBytes("UTF-8"));
			encodestr = byte2Hex(messageDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return encodestr;
	}

	/**
	 * 将byte转为16进制
	 *
	 * @param bytes
	 * @return
	 */
	private static String byte2Hex(byte[] bytes) {
		StringBuffer stringBuffer = new StringBuffer();
		String temp = null;
		for (int i = 0; i < bytes.length; i++) {
			temp = Integer.toHexString(bytes[i] & 0xFF);
			if (temp.length() == 1) {
				//1得到一位的进行补0操作
				stringBuffer.append("0");
			}
			stringBuffer.append(temp);
		}
		return stringBuffer.toString();
	}
}
@Component
public class SignAuthFilter implements Filter {
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

		// 签名的验证
//		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletRequest request = new BodyReaderHttpServletRequestWrapper((HttpServletRequest)servletRequest);

		HttpServletResponse response = (HttpServletResponse) servletResponse;

		// 获取参数.统一get和post,不管url,还是 body
		SortedMap<String, String> allParams = HttpParamUtils.getAllParams(request);

		// 校验签名
		boolean b = CheckUtils.checkSign(allParams);
		System.out.println("校验签名结果:"+b);
		if (b){
			filterChain.doFilter(request,response);
		}else {
			response.setCharacterEncoding("utf-8");
			response.setContentType("application/json;charset=utf-8");
			PrintWriter writer = response.getWriter();

			JSONObject param = new JSONObject();
			param.put("code",-1);
			param.put("message", "签名错了");

			writer.append(param.toJSONString());
		}


		System.out.println("filter生效了");
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("初始化");
	}

	@Override
	public void destroy() {
		System.out.println("销毁");
	}
}
/**
 * 保存过滤器里面的流
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
 
    private final byte[] body;
 
    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        String sessionStream = getBodyString(request);
        body = sessionStream.getBytes(Charset.forName("UTF-8"));
    }
 
    /**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    public String getBodyString(final ServletRequest request) {
 
        StringBuilder sb = new StringBuilder();
        try (
            InputStream inputStream = cloneInputStream(request.getInputStream());
            BufferedReader 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();
        }
        return sb.toString();
    }
 
    /**
     * Description: 复制输入流</br>
     */
    public InputStream cloneInputStream(ServletInputStream inputStream) {
 
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        try {
            while ((len = inputStream.read(buffer)) > -1) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            byteArrayOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
 
    @Override
    public BufferedReader getReader() {
 
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
 
    @Override
    public ServletInputStream getInputStream() {
 
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
 
            @Override
            public int read() {
 
                return bais.read();
            }
 
            @Override
            public boolean isFinished() {
 
                return false;
            }
 
            @Override
            public boolean isReady() {
 
                return false;
            }
 
            @Override
            public void setReadListener(ReadListener readListener) {
 
            }
        };
    }
}
@Slf4j
public class HttpParamUtils {
	/**
	 * 获取所有参数,包括 url和body
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public static SortedMap<String,String> getAllParams(HttpServletRequest request) throws IOException {

		// 获取 url上的参数
		Map<String, String> urlParams = getUrlParams(request);
		System.out.println("url 参数:"+urlParams);

		// 获取 body上的参数
		Map<String, String> bodyParams = getBodyParams(request);

		// 总的参数的map
		SortedMap<String , String> allMap = new TreeMap<>();
		for (Map.Entry entry : urlParams.entrySet()){
			allMap.put((String) entry.getKey() , (String)entry.getValue());
		}
		for (Map.Entry entry : bodyParams.entrySet()){
			allMap.put((String) entry.getKey() , (String)entry.getValue());
		}

		log.info("所有的参数:"+allMap);

		return allMap;
	}

	/**
	 * 获取body中的参数
	 */
	private static Map<String,String> getBodyParams(HttpServletRequest request) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())) ;

		StringBuilder sb = new StringBuilder();
		// 读取 流
		String s = "";
		while ((s=reader.readLine())!=null){
			sb.append(s);
		}

		// 转map
		Map map = JSONObject.parseObject(sb.toString(), Map.class);

		System.out.println("body参数:"+map);
		return map;

	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值