基于SpringMVC的HTTP+JSON签名校验

客户端

Client.java

/**
     * 向服务器发送请求并解析返回响应结果
     * @param url - 请求的地址
     * @param baseClientDTO - 请求的参数
     * @param type - 返回参数的类型
     * @return 返回参数实例
     * @throws IOException
     */
    public static <T> T sendAndReturn(String url, BaseClientDTO baseClientDTO, TypeReference<T> type) throws IOException {
        //TODO 基于hmac256(baseClientDTO,secretKey)签名,服务器同样签名后比对,相同为真,不同为否
        String param = JSON.toJSONString(baseClientDTO);
        URL realUrl = new URL(url);
        // 打开和URL之间的连接
        HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection();
        // 设置通用的请求属性
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(20000);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestMethod("POST");
        connection.setUseCaches(false);
        connection.setInstanceFollowRedirects(true);
        connection.setRequestProperty("Content-Type","application/json;charset=utf-8");
        //签名设置
        String secretKey = OccDownloadService.getInstance().secretKey;
        String signature = null;
        if (secretKey != null) {
            signature = SecretUtil.hmac256(param,secretKey);
        }
        connection.setRequestProperty("signature", signature);

        connection.setRequestProperty("envCode", baseClientDTO.getEnvCode());
        connection.setRequestProperty("nsCode", baseClientDTO.getNsCode());
        connection.setRequestProperty("clientLocalIp",_CLIENT_LOCAL_IP);
        connection.connect();
        PrintWriter out = null;
    	BufferedReader br = null;
    	InputStreamReader ir = null;
        try {
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(connection.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            //是否请求成功
            InputStream inputStream = (connection.getResponseCode() == HttpURLConnection.HTTP_OK) ?
                                        connection.getInputStream() :
                                        connection.getErrorStream();
            //获取数据
            br = new BufferedReader(ir = new InputStreamReader(inputStream,"UTF-8"));
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = br.readLine()) != null) {
                result.append(line);
            }
            return JSON.parseObject(result.toString(), type);
        }finally {
            close(out,br,ir);
            connection.disconnect();
        }
    }

SecretUtil.java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by Think on 2017/3/20.
 */
public class SecretUtil {

    /**
     * 签名加密
     *
     * @param str
     * @param stal
     * @return
     */
    public static String hmac256(String str, String stal) {
        Mac hmac;
        try {
            hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec macKey = new SecretKeySpec(stal.getBytes(), "RAW");
            hmac.init(macKey);
            byte[] key = hmac.doFinal(str.getBytes());
            return byteToHexString(key);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Hex转换
     *
     * @param bt
     * @return
     */
    public static String byteToHexString(byte[] bt) {
        StringBuilder stringBuilder = new StringBuilder("");
        for (byte aSrc : bt) {
            int v = aSrc & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

}

服务端

SecretKeyFilter.java

import com.odianyun.cc.business.utils.SpringContextUtil;
import com.odianyun.cc.business.write.manage.IOccSecretKeyManage;
import com.odianyun.cc.model.dto.OccSecretKeyDTO;
import com.odianyun.cc.model.util.SecretUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class SecretKeyFilter implements Filter{

	private static final Logger logger = LoggerFactory.getLogger(SecretKeyFilter.class);

	private static final String EXCLUDE_CONFIG_NAME = "excludeURL";

	private SecretKeyFilterConfig secretKeyFilterConfig;
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("--------------------SecretKeyFilter-------------init ");
		}
		String excludeConfig = filterConfig.getInitParameter(EXCLUDE_CONFIG_NAME);
		this.secretKeyFilterConfig = SecretKeyFilterConfig.getInstance(excludeConfig);
	}

	private String getRequetUriExcludeContextPath(HttpServletRequest req) {
		String requestUrl = req.getRequestURI();
		String contextPath = req.getContextPath();
		String reqPath = requestUrl.replace(contextPath, "");
		while(reqPath.startsWith("//")){
			reqPath = reqPath.replaceFirst("//","/");
		}
		if (logger.isDebugEnabled()) {
			logger.debug("requestUrl={},contextPath={},reqPath={}", requestUrl, contextPath, reqPath);
		}
		return reqPath;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest)request;
		String requestUri = this.getRequetUriExcludeContextPath(req);
		if (this.secretKeyFilterConfig.match(requestUri)){
			chain.doFilter(request, response);
			return;
		}
	    String envCode = req.getHeader("envCode");
	    String nsCode  = req.getHeader("nsCode");

        if(StringUtils.isNotBlank(envCode) && StringUtils.isNotBlank(nsCode)){
        	OccSecretKeyDTO dto = new OccSecretKeyDTO();
        	dto.setEnvCode(envCode);
        	dto.setNsCode(nsCode);
        	IOccSecretKeyManage occSecretKeyManage = SpringContextUtil.getBean(IOccSecretKeyManage.class);
        	try {
        		dto = occSecretKeyManage.selectOneSecretkey(dto);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}

			if(dto == null){
				chain.doFilter(request, response);
				return;
			}

			//签名校验 add by jdkleo @ 2017-03-21 11:06
			ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(req);
			String body = HttpHelper.getBodyString(requestWrapper);
			String signature = req.getHeader("signature");//签名
			String signatureString = SecretUtil.hmac256(body, dto.getSecretKey());//按原文进行签名计算
			if (signatureString.equals(signature)){//比较服务器签名和客户端签名
				chain.doFilter(requestWrapper, response);
				return;
			}
        }
	}

	@Override
	public void destroy() {
		
	}

}

BodyReaderHttpServletRequestWrapper.java

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;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;


public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private final byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        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 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);
    }

}


HttpHelper.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import javax.servlet.ServletRequest;

public class HttpHelper {
    /**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    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();
                }
            }
        }
        return sb.toString();
    }
}

猜你喜欢

转载自jdkleo.iteye.com/blog/2364583