com.taobao.api.internal.spi.SpiUtils Maven / Gradle / Ivy
The newest version!
package com.taobao.api.internal.spi;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.taobao.api.Constants;
import com.taobao.api.internal.util.StringUtils;
import com.taobao.api.internal.util.TaobaoUtils;
import com.taobao.api.internal.util.WebUtils;
/**
* SPI服务提供方工具类。
*/
public class SpiUtils {
private static final Log log = LogFactory.getLog(SpiUtils.class);
private static final String TOP_SIGN_LIST = "top-sign-list";
private static final String[] HEADER_FIELDS_IP = { "X-Real-IP", "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR" };
/**
* 校验SPI请求签名,不支持带上传文件的HTTP请求。
*
* @param request HttpServletRequest对象实例
* @param secret APP密钥
* @return 校验结果
*/
public static CheckResult checkSign(HttpServletRequest request, String secret) throws IOException {
CheckResult result = new CheckResult();
String ctype = request.getContentType();
String charset = WebUtils.getResponseCharset(ctype);
if (ctype.startsWith(Constants.CTYPE_APP_JSON) ||
ctype.startsWith(Constants.CTYPE_TEXT_XML) ||
ctype.startsWith(Constants.CTYPE_APPLICATION_XML) ||
ctype.startsWith(Constants.CTYPE_TEXT_PLAIN)) {
String body = WebUtils.getStreamAsString(request.getInputStream(), charset);
boolean valid = checkSignInternal(request, null, body, secret, charset);
result.setSuccess(valid);
result.setRequestBody(body);
} else if (ctype.startsWith(Constants.CTYPE_FORM_DATA)) {
boolean valid = checkSignInternal(request, null, null, secret, charset);
result.setSuccess(valid);
} else {
throw new RuntimeException("Unspported SPI request");
}
return result;
}
/**
* 校验SPI请求签名,适用于所有GET请求,及不包含文件参数的POST请求。
*
* @param request 请求对象
* @param secret app对应的secret
* @return true:校验通过;false:校验不通过
* @deprecated 请使用checkSign方法
*/
public static boolean checkSign4FormRequest(HttpServletRequest request, String secret) throws IOException {
String charset = WebUtils.getResponseCharset(request.getContentType());
return checkSignInternal(request, null, null, secret, charset);
}
/**
* 校验SPI请求签名,适用于请求体是xml/json等可用文本表示的POST请求。
*
* @param request 请求对象
* @param body 请求体的文本内容
* @param secret app对应的secret
* @return true:校验通过;false:校验不通过
* @deprecated 请使用checkSign方法
*/
public static boolean checkSign4TextRequest(HttpServletRequest request, String body, String secret) throws IOException {
String charset = WebUtils.getResponseCharset(request.getContentType());
return checkSignInternal(request, null, body, secret, charset);
}
/**
* 校验SPI请求签名,适用于带文件上传的POST请求。
*
* @param request 请求对象
* @param form 除了文件参数以外的所有普通文本参数的map集合
* @param secret app对应的secret
* @return true:校验通过;false:校验不通过
*/
public static boolean checkSign4FileRequest(HttpServletRequest request, Map form, String secret) throws IOException {
String charset = WebUtils.getResponseCharset(request.getContentType());
return checkSignInternal(request, form, null, secret, charset);
}
private static boolean checkSignInternal(HttpServletRequest request, Map form, String body, String secret, String charset) throws IOException {
Map params = new HashMap();
// 1. 获取header参数
Map headerMap = getHeaderMap(request, charset);
params.putAll(headerMap);
// 2. 获取url参数
Map queryMap = getQueryMap(request, charset);
params.putAll(queryMap);
// 3. 获取form参数
if (form == null && body == null) {
Map formMap = getFormMap(request, queryMap);
params.putAll(formMap);
} else if (form != null) {
params.putAll(form);
}
// 4. 生成签名并校验
String remoteSign = queryMap.get(Constants.SIGN);
String localSign = sign(params, body, secret, charset);
if (localSign.equals(remoteSign)) {
return true;
} else {
String paramStr = getParamStrFromMap(params);
log.error("checkTopSign error^_^remoteSign=" + remoteSign + "^_^localSign=" + localSign + "^_^paramStr=" + paramStr + "^_^body=" + body);
return false;
}
}
/**
* 获取header参数为map
*/
public static Map getHeaderMap(HttpServletRequest request, String charset) throws IOException {
Map headerMap = new HashMap();
String signList = request.getHeader(TOP_SIGN_LIST); // 只获取参与签名的头部字段
if (!StringUtils.isEmpty(signList)) {
String[] keys = signList.split(",");
for (String key : keys) {
String value = request.getHeader(key);
if (StringUtils.isEmpty(value)) {
headerMap.put(key, "");
} else {
headerMap.put(key, URLDecoder.decode(value, charset));
}
}
}
return headerMap;
}
/**
* 获取url参数为map
*/
public static Map getQueryMap(HttpServletRequest request, String charset) throws IOException {
Map queryMap = new HashMap();
String queryString = request.getQueryString();
String[] params = queryString.split("&");
for (int i = 0; i < params.length; i++) {
String[] kv = params[i].split("=");
if (kv.length == 2) {
String key = URLDecoder.decode(kv[0], charset);
String value = URLDecoder.decode(kv[1], charset);
queryMap.put(key, value);
} else if (kv.length == 1) { // 参数值为空
String key = URLDecoder.decode(kv[0], charset);
queryMap.put(key, "");
}
}
return queryMap;
}
/**
* 获取表单参数为map
*/
public static Map getFormMap(HttpServletRequest request, Map queryMap) throws IOException {
Map formMap = new HashMap();
Set> keys = request.getParameterMap().keySet();
for (Object tmp : keys) {
String key = String.valueOf(tmp);
if (!queryMap.containsKey(key)) {
String value = request.getParameter(key);
if (StringUtils.isEmpty(value)) {
formMap.put(key, "");
} else {
formMap.put(key, value);
}
}
}
return formMap;
}
/**
* 获取body为字符串
*/
public static String getStreamAsString(InputStream stream, String charset) throws IOException {
return WebUtils.getStreamAsString(stream, charset);
}
/**
* 签名规则:hex(md5(secret+sorted(header_params+url_params+form_params)+body+secret)
*/
private static String sign(Map params, String body, String secret, String charset) throws IOException {
StringBuilder sb = new StringBuilder(secret);
sb.append(getParamStrFromMap(params));
if (body != null) {
sb.append(body);
}
sb.append(secret);
byte[] bytes = TaobaoUtils.encryptMD5(sb.toString().getBytes(charset));
return TaobaoUtils.byte2hex(bytes);
}
private static String getParamStrFromMap(Map params) {
StringBuilder sb = new StringBuilder();
if (params != null && !params.isEmpty()) {
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
for (int i = 0; i < keys.length; i++) {
String name = keys[i];
if (!Constants.SIGN.equals(name)) {
sb.append(name);
sb.append(params.get(name));
}
}
}
return sb.toString();
}
/**
* 检查SPI请求到达服务器端是否已经超过指定的分钟数,如果超过则拒绝请求。
*
* @return true代表不超过,false代表超过。
*/
public static boolean checkTimestamp(HttpServletRequest request, int minutes) {
String ts = request.getParameter(Constants.TIMESTAMP);
if (ts != null) {
long remote = StringUtils.parseDateTime(ts).getTime();
long local = Calendar.getInstance().getTime().getTime();
return (local - remote) <= minutes * 60 * 1000L;
} else {
return false;
}
}
/**
* 检查发起SPI请求的来源IP是否是TOP机房的出口IP。
*
* @param request HTTP请求
* @param topIpList TOP网关IP出口地址段列表,通过taobao.top.ipout.get获得
*
* @return true表达IP来源合法,false代表IP来源不合法
*/
public static boolean checkRemoteIp(HttpServletRequest request, List topIpList) {
String ip = request.getRemoteAddr();
for (String ipHeader : HEADER_FIELDS_IP) {
String realIp = request.getHeader(ipHeader);
if (!StringUtils.isEmpty(realIp) && !"unknown".equalsIgnoreCase(realIp)) {
ip = realIp;
break;
}
}
if (topIpList != null) {
for (String topIp : topIpList) {
if (StringUtils.isIpInRange(ip, topIp)) {
return true;
}
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy