说明
HttpClient是一个常用的Java HTTP客户端库,可以用来发送HTTP请求并接收响应。一般再对接其他服务接口时,会需要引入签名验签机制,本文据HttpClient调用接口和引入签名验签使用示例。
引入签名验签步骤:
-
- 定义签名算法和验签算法:根据具体业务需求,选择合适的签名算法和验签算法。常用的签名算法包括HMAC-SHA1、HMAC-SHA256等,常用的验签算法包括RSA、DSA等。
-
- 在请求中添加签名信息:在发送请求之前,需要根据选定的签名算法对请求参数进行签名,并将签名结果添加到请求头或请求参数中。签名信息可以用Base64编码或其他方式进行编码。
-
- 在接收响应时进行验签:接收到响应后,需要从响应头或响应参数中获取签名信息,并使用选定的验签算法对响应结果进行验签。如果验签成功,则可以认为响应结果是可信的;如果验签失败,则应该丢弃响应结果或进行其他处理。
依赖引入
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
或者
compile 'com.google.code.gson:gson:2.8.6'
compile 'org.apache.httpcomponents:httpclient:4.5.12'
compile 'org.apache.commons:commons-lang3:3.9'
Get请求
import kl.idaas.util.TokenUtils;
import com.google.gson.Gson;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
/**
* 拉取接口调用示例代码
*/
public class PullDataDemo {
public static void main(String[] args) throws Exception {
//接口地址,详见接口定义
String restSever = "http://xxx.xxxx.com/service/pull/orgs";
// 标识
String appKey = "xxxxxxxxxxxxxxxxxxx";
// 系统签发给应用对接的密钥
String pwd = "xxxxxxxxxxxxxxxxxxx";
// 时间戳
Long ts = Calendar.getInstance().getTime().getTime();
// 随机数
String once = RandomStringUtils.randomAlphanumeric(32);
String signMethod = "SHA-256";
// 创建HttpClient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String commonParamUrl = String.format("appKey=%s" + "&" + "ts=%s" + "&" + "once=%s" + "&" + "signMethod=%s", appKey, ts, once, signMethod);
//循环拉取,直至数据拉取完毕
//首次调用时填写0,之后调用填写系统已持久化存储的数据中最大的syncSequence
Long syncSequence = 0L;
while (true) {
String getQueryParam = "syncSequence="+syncSequence;
String getFullUrl = restSever + "?" + getQueryParam;
HttpGet httpGet = new HttpGet(getFullUrl);
String getAllParamUrl = commonParamUrl + "&" + getQueryParam;
System.out.println("请求参数:" + getAllParamUrl);
// 签名数据
String signData = TokenUtils.getSignature(pwd, getAllParamUrl);
// 添加header参数 appCode、timestamp、 signatureNonce、signature
httpGet.addHeader("appKey", appKey);
httpGet.addHeader("ts", ts.toString());
httpGet.addHeader("once", once);
httpGet.addHeader("signMethod", signMethod);
System.out.println("once:" + once);
httpGet.addHeader("signData", signData);
System.out.println("headers:" + Arrays.toString(httpGet.getAllHeaders()));
String urlStr = httpGet.getURI().toString();
// 公共参数URL
System.out.println("commonParamter:" + urlStr);
if (StringUtils.endsWith(urlStr, "/")) {
urlStr = StringUtils.removeEnd(urlStr, "/");
}
httpGet.setURI(new URI(urlStr));
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
.setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();
httpGet.setConfig(requestConfig);
System.out.println("urlStr in request:" + httpGet.getURI().toString());
// 执行请求
CloseableHttpResponse response = httpclient.execute(httpGet);
// 取响应的结果
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
return;
}
HttpEntity entity = response.getEntity();
Gson gson=new GsonBuilder().registerTypeAdapter(Map.class, new JsonDeserializer<Map>() {
@Override
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException{
Map<String,Object> resultMap=new HashMap<>(32);
JsonObject jsonObject = json.getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
resultMap.put(entry.getKey(),entry.getValue());
}
return resultMap;
}
}).create();
Map<String, Object> parseObject = gson.fromJson(EntityUtils.toString(entity), Map.class);
//todo 对获取的数据进行操作
Object result = parseObject.get("result");
System.out.println("result=" + result);
JsonArray arr = (JsonArray)result;
//判断数据是否同步结束
if(arr == null || arr.size() == 0) {
//数据同步已完成
break;
}
int size = arr.size();
for (int i = 0; i < arr.size(); i++) {
JsonObject obj = arr.get(i).getAsJsonObject();
//obj中获取属性值,如userName
String orgName = obj.get("userName").getAsString();
System.out.println("userName=" + userName);
if(i == size - 1) {
//获取本次拉取数据中最大的maxSyncSequence,作为下次的参数
syncSequence = Long.valueOf(obj.get("syncSequence").toString());
}
}
System.out.println("maxSyncSequence=" + syncSequence);
}
}
}
Post使用form-data请求
import com.google.gson.Gson;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.util.*;
/**
* Post使用form-data请求
**/
public class HttpClientUtils {
public static void main(String[] args) throws Exception {
//接口地址
String restSever = "http://127.0.0.1:8080/service/base/user/pwd/modify";
// 应用标识
String appKey = "xxxxxxxxxxxxxxxxxxx";
// 系统签发给应用对接的密钥
String pwd = "xxxxxxxxxxxxxxxxxxx";
// 时间戳
Long ts = Calendar.getInstance().getTime().getTime();
// 随机数
String once = RandomStringUtils.randomAlphanumeric(32);
String signMethod = "SHA-256";
// 创建HttpClient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String commonParamUrl = String.format("appKey=%s" + "&" + "ts=%s" + "&" + "once=%s" + "&" + "signMethod=%s", appKey, ts, once, signMethod);
HttpPost httpPost = new HttpPost(restSever);
// 签名数据
String signData = TokenUtils.getSignature(pwd, restSever);
// 添加header参数 appCode、timestamp、 signatureNonce、signature
httpPost.addHeader("appKey", appKey);
httpPost.addHeader("ts", ts.toString());
httpPost.addHeader("once", once);
httpPost.addHeader("once", once);
httpPost.addHeader("signMethod", signMethod);
System.out.println("once:" + once);
httpPost.addHeader("signData", signData);
httpPost.addHeader("tenantId", "1");
System.out.println("headers:" + Arrays.toString(httpPost.getAllHeaders()));
String urlStr = httpPost.getURI().toString();
// 公共参数URL
System.out.println("commonParamter:" + urlStr);
if (StringUtils.endsWith(urlStr, "/")) {
urlStr = StringUtils.removeEnd(urlStr, "/");
}
httpPost.setURI(new URI(urlStr));
//httpClient 4.5版本的超时参数配置
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
.setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();
httpPost.setConfig(requestConfig);
System.out.println("urlStr in request:" + httpPost.getURI().toString());
//使用form-data格式往BODY里填充数据主体
List<NameValuePair> parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair("newPwd", "123456"));
parameters.add(new BasicNameValuePair("oldPwd", "123456"));
parameters.add(new BasicNameValuePair("userId", "xxxxxxxxxxxxxxxxxxx"));
HttpEntity entity = new UrlEncodedFormEntity(parameters,"utf-8");
httpPost.setEntity(entity);
// 执行请求
CloseableHttpResponse response = httpclient.execute(httpPost);
// 取响应的结果
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("statusCode:" + statusCode);
HttpEntity responseEntity = response.getEntity();
Gson gson = new Gson();
Map<String, Object> parseObject = gson.fromJson(EntityUtils.toString(responseEntity), Map.class);
System.out.println("r:" + parseObject);
//todo 对返回值进行处理
String code = parseObject.get("code").toString();
System.out.println("code:" + code);
if(!"0".equals(code)) {
System.out.println("error:" + parseObject.get("message").toString());
}
Object records = parseObject.get("result");
}
}
Post使用Json请求(统一常用)
import com.google.gson.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.*;
public class ResetPwd {
public static void main(String[] args) throws Exception {
//接口地址
String restSever = "http://xxxxx:8080/service/base/user/pwd/modify";
// 应用标识
String appKey = "xxxxxxxxxxxxxxxxxxx";
// 系统签发给应用对接的密钥
String pwd = "xxxxxxxxxxxxxxxxxxx";
// 时间戳
Long ts = Calendar.getInstance().getTime().getTime();
// 随机数
String once = RandomStringUtils.randomAlphanumeric(32);
String signMethod = "SHA-256";
JsonObject obj = new JsonObject();
//请求参数
obj.addProperty("userId", "xxxxxxxxxxxxxxxxx");
obj.addProperty("oldPwd", "123456");
obj.addProperty("newPwd", "180127");
String bodyData = obj.toString();
String commonParamUrl = String.format("appKey=%s" + "&" + "bodyData=%s" + "&" + "ts=%s" + "&" + "once=%s" + "&" + "signMethod=%s", appKey, bodyData, ts, once, signMethod);
HttpPost httpPost = new HttpPost(restSever);
System.out.println("请求参数:" + commonParamUrl);
// 签名数据
String signData = TokenUtils.getSignature(pwd, commonParamUrl);
// 添加header参数 appCode、timestamp、 signatureNonce、signature
httpPost.addHeader("Content-Type", "application/json;charset=utf-8");
httpPost.addHeader("appKey", appKey);
httpPost.addHeader("ts", ts.toString());
httpPost.addHeader("once", once);
httpPost.addHeader("signMethod", signMethod);
System.out.println("once:" + once);
httpPost.addHeader("signData", signData);
System.out.println("headers:" + Arrays.toString(httpPost.getAllHeaders()));
httpPost.setEntity(new StringEntity(bodyData));
String urlStr = httpPost.getURI().toString();
// 公共参数URL
System.out.println("commonParamter:" + urlStr);
if (StringUtils.endsWith(urlStr, "/")) {
urlStr = StringUtils.removeEnd(urlStr, "/");
}
httpPost.setURI(new URI(urlStr));
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
.setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();
httpPost.setConfig(requestConfig);
System.out.println("urlStr in request:" + httpPost.getURI().toString());
// 创建HttpClient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 执行请求
CloseableHttpResponse response = httpclient.execute(httpPost);
// 取响应的结果
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("statusCode:" + statusCode);
HttpEntity entity = response.getEntity();
Gson gson = new Gson();
Map<String, Object> parseObject = gson.fromJson(EntityUtils.toString(entity), Map.class);
System.out.println("r:" + parseObject);
//todo 对返回值进行处理
String code = parseObject.get("code").toString();
System.out.println("code:" + code);
if(!"0".equals(code)) {
System.out.println("error:" + parseObject.get("message").toString());
}
Object records = parseObject.get("result");
}
}
签名验签处理方法类
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* 签名方法类
*/
public class TokenUtils {
private static final Logger logger = LoggerFactory.getLogger(TokenUtils.class);
private static String[] hexDigits = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e",
"f"};
public static String getSignature(String pwd, String paramUrl) {
if (StringUtils.isNotBlank(paramUrl)) {
try {
paramUrl = URLDecoder.decode(paramUrl, "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error("生成signData失败:", e);
throw new RuntimeException("生成signData失败:", e);
}
}
String[] paraArray = new String[]{
};
if (StringUtils.isNotBlank(paramUrl)) {
String[] queryArray = paramUrl.split("&");
paraArray = (String[]) ArrayUtils.addAll(queryArray, paraArray);
}
Arrays.sort(paraArray);
StringBuffer buffer = new StringBuffer();
buffer.append(pwd);
buffer.append(":");
for (int i = 0; i < paraArray.length; i++) {
buffer.append(paraArray[i]);
buffer.append("&");
}
buffer.deleteCharAt(buffer.length() - 1);
buffer.append(":");
buffer.append(pwd);
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(buffer.toString().getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
logger.error("生成signData失败:", e);
throw new RuntimeException("生成signData失败.", e);
} catch (UnsupportedEncodingException e) {
logger.error("生成signData失败:", e);
throw new RuntimeException("生成signData失败.", e);
}
String encode = byteArrayToHexString(md.digest());
return encode;
}
private static String byteArrayToHexString(byte[] byteArray) {
StringBuffer sb = new StringBuffer();
for (byte byt : byteArray) {
sb.append(byteToHexString(byt));
}
return sb.toString();
}
private static String byteToHexString(byte byt) {
int n = byt;
if (n < 0)
n = 256 + n;
return hexDigits[n / 16] + hexDigits[n % 16];
}
}