zoukankan      html  css  js  c++  java
  • java Http传输md5签名工具类

    从客户端转为服务端日记(一)

    应用场景:

    应用A请求应用B为保障数据不被非法篡改我们通常会对数据进行md5加密。

    加密算法流程:

    1.加入时间戳参数

    2.根据字典树对请求的参数(Map<String,String>)进行冒泡排序。

    3.对数据进行格式化==> A=a&B=b&timestamp=121364565。

    4.对格式化后的参数进行加密并加在格式化参数的末尾

    验证算法流程

    1.取出Map中的sigin

    2.直接将map格式化并加密。比较md5是否一致


    我将这个类用于拦截器中。当配置的请求非法时自动返回错误信息。


    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.SortedMap;
    import java.util.TreeMap;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    public class SignedRequestHelperTest {
    
    	private static final String UTF8 = "UTF-8";
    	private static final String HMAC_SHA256 = "HmacSHA256";
    
    	private String secretKey = "myscretKey";
    
    	private Mac mac;
    	private String urlParams;
    
    	public SignedRequestHelperTest(){
    		init();
    	}
    
    	private void init() {
    		try {
    			byte[] secretyKeyBytes = secretKey.getBytes(UTF8);
    			SecretKeySpec secretKeySpec = new SecretKeySpec(secretyKeyBytes, HMAC_SHA256);
    			mac = Mac.getInstance(HMAC_SHA256);
    			mac.init(secretKeySpec);
    		} catch (UnsupportedEncodingException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (NoSuchAlgorithmException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (InvalidKeyException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 
    	 * @param params
    	 * @return 没有urlecode的签名 params中sign是urlecode的签名
    	 */
    	public String sign(Map<String, String> params) {
    		if (!params.containsKey("timestamp")) {
    			params.put("timestamp", timestamp());
    		}
    		SortedMap<String, String> sortedParamMap = new TreeMap<String, String>(params);
    		String canonicalQS = canonicalize(sortedParamMap);
    		String toSign = canonicalQS;
    		System.out.println(toSign);
    		String hmac = hmac(toSign);
    		String signed = percentEncodeRfc3986(hmac);
    		params.put("sign", signed);
    		sortedParamMap = new TreeMap<String, String>(params);
    		this.setUrlParams(canonicalize(sortedParamMap));
    		return signed;
    	}
    
    	public boolean validSign(Map<String, String> params) {
    		if (params.containsKey("sign")) {
    			String sign1 = params.get("sign");
    			params.remove("sign");
    			String sign2 = sign(params);
    			//System.out.println(sign1);
    			//System.out.println(sign2);
    			if (sign2.equals(sign1)) {
    				return true;
    			}
    		}
    		return false;
    	}
    
    	private String hmac(String stringToSign) {
    		String signature = null;
    		byte[] data;
    		byte[] rawHmac;
    		try {
    			data = stringToSign.getBytes(UTF8);
    			rawHmac = mac.doFinal(data);
    			Base64 encoder = new Base64();
    			signature = new String(encoder.encode(rawHmac));
    		} catch (UnsupportedEncodingException e) {
    			throw new RuntimeException(UTF8 + " is unsupported!", e);
    		}
    		return signature;
    	}
    
    	/**
    	 * @return
    	 */
    	private String timestamp() {
    		return System.currentTimeMillis() + "";
    	}
    
    	/**
    	 * @param sortedParamMap
    	 * @return
    	 */
    	private String canonicalize(SortedMap<String, String> sortedParamMap) {
    		if (sortedParamMap.isEmpty()) {
    			return "";
    		}
    		StringBuffer buffer = new StringBuffer();
    		Iterator<Map.Entry<String, String>> iter = sortedParamMap.entrySet().iterator();
    		while (iter.hasNext()) {
    			Map.Entry<String, String> kvpair = iter.next();
    			buffer.append(percentEncodeRfc3986(kvpair.getKey()));
    			buffer.append("=");
    			buffer.append(percentEncodeRfc3986(kvpair.getValue()));
    			if (iter.hasNext()) {
    				buffer.append("&");
    			}
    		}
    		String canonical = buffer.toString();
    		return canonical;
    	}
    
    	/**
    	 * Rfc3986</br>
    	 * 此处建议使用spring的encodeUri方法
    	 * http://docs.spring.io/spring/docs/4.0.x/javadoc-api/org/springframework/
    	 * web/util/UriUtils.html
    	 * 
    	 * @param s
    	 * @return
    	 */
    	private String percentEncodeRfc3986(String s) {
    		String out;
    		try {
    			out = URLEncoder.encode(s, UTF8).replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
    		} catch (UnsupportedEncodingException e) {
    			out = s;
    		}
    		return out;
    	}
    
    	public String getUrlParams() {
    		return urlParams;
    	}
    
    	public void setUrlParams(String urlParams) {
    		this.urlParams = urlParams;
    	}
    
    	public static void main(String[] args) throws Exception {
    		SignedRequestHelperTest signReqHelper = new SignedRequestHelperTest();
    		Map<String, String> params = new HashMap<String, String>();
    		params.put("uname", "username");
    		params.put("passwd", "password");
    		params.put("a", "a");
    		System.out.println(signReqHelper.sign(params));
    		System.out.println(signReqHelper.validSign(params));
    	}
    }
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.fh.controller.base.BaseController;
    import com.fh.util.SignedRequestHelper;
    
    
    public class MD5Filter extends BaseController implements Filter {
    
    	@Override
    	public void destroy() {
    		// TODO Auto-generated method stub
    		
    	}
    
    	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
    			throws IOException, ServletException {
    		logBefore(logger, "验证签名开始");
    		HttpServletRequest request = (HttpServletRequest) req;
    		HttpServletResponse response = (HttpServletResponse) res;
    		Enumeration e = (Enumeration) request.getParameterNames();
    		Map<String, String> map = new HashMap();
    		while (e.hasMoreElements()) {
    			String key = (String)e.nextElement();
    			map.put(key, request.getParameter(key));
    		}
    		
    		try {
    			SignedRequestHelper sign = new SignedRequestHelper();
    			System.out.println(sign.validSign(map));
    			if(sign.validSign(map)){
    				chain.doFilter(req, res); // 调用下一过滤器
    				return;
    			}
    		} catch (Exception e2) {
    			// TODO: handle exception
    			logBefore(logger, "验证签名异常");
    		}
    		response.setHeader("Content-type", "text/html;charset=UTF-8"); 
    		response.setCharacterEncoding("utf-8");
    		PrintWriter out = response.getWriter();
    		
    
    		String reString = "{"errcode":10003,"data":{},"errmsg":"签名错误"}";
    	
    		out.write(reString);
    	}
    
    	@Override
    	public void init(FilterConfig arg0) throws ServletException {
    		// TODO Auto-generated method stub
    		
    	}
    	
    	
    }


  • 相关阅读:
    【做题记录】区间排序—线段树
    【做题记录】CF1428E Carrots for Rabbits—堆的妙用
    线段树合并、分裂
    一、drf入门规范
    七、Django实战--图书管理系统搭建
    六、ORM模型层补充
    五、Django之模型层
    四、Django之模板层
    三、Django之视图层
    二、Django之路由层
  • 原文地址:https://www.cnblogs.com/leejuen/p/5547441.html
Copyright © 2011-2022 走看看