package com.hdl.sdk.connect.cloud.interceptor;
|
|
import android.net.Uri;
|
import android.text.TextUtils;
|
|
import androidx.annotation.NonNull;
|
|
import com.google.gson.JsonElement;
|
import com.google.gson.JsonObject;
|
import com.google.gson.JsonParser;
|
import com.google.gson.reflect.TypeToken;
|
import com.hdl.sdk.connect.HDLLink;
|
import com.hdl.sdk.connect.cloud.GsonUtils;
|
import com.hdl.sdk.connect.cloud.MD5Utils;
|
import com.hdl.sdk.connect.config.HDLCloudConfig;
|
|
import java.io.IOException;
|
import java.net.URLDecoder;
|
import java.nio.charset.Charset;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
|
import okhttp3.FormBody;
|
import okhttp3.Headers;
|
import okhttp3.Interceptor;
|
import okhttp3.MediaType;
|
import okhttp3.Request;
|
import okhttp3.RequestBody;
|
import okhttp3.Response;
|
import okio.Buffer;
|
|
/**
|
* Created by Tong on 2021/11/4.
|
* 加密并自动补充参数,appKey、timestamp
|
* 只支持表单、json
|
* 最终json方式提交
|
*/
|
public class EncryptInterceptor implements Interceptor {
|
|
|
@NonNull
|
@Override
|
public Response intercept(@NonNull Chain chain) throws IOException {
|
Request request = chain.request();
|
Headers headers = request.headers();
|
if (!isIgnoreSignHeader(headers)) {
|
return chain.proceed(encrypt(request));
|
}
|
|
return chain.proceed(request);
|
}
|
|
|
/**
|
* 添加sign字段
|
*/
|
private Request encrypt(Request request) {
|
final String timestamp = String.valueOf(System.currentTimeMillis());
|
final String appKey = HDLCloudConfig.getInstance().getAppKey();
|
final String appSecret = HDLCloudConfig.getInstance().getAppSecret();
|
final JsonObject json = getBodyJson(request);
|
if (json != null) {
|
json.addProperty("appKey", appKey);
|
json.addProperty("timestamp", timestamp);
|
json.addProperty("sign", getSign(json, appSecret));
|
final RequestBody requestBody = RequestBody.create(json.toString(), MediaType.parse("application/json;charset=UTF-8"));
|
return request.newBuilder().post(requestBody)
|
.build();
|
}
|
return request;
|
}
|
|
/**
|
* 需要按字母排序
|
*
|
* @param json 所有字段使用urlParameter拼接,除了appSecret
|
*/
|
private String getSign(JsonObject json, String appSecret) {
|
String builder = jsonToUrlParameter(json) +
|
appSecret;
|
return MD5Utils.encodeMD5(builder);
|
}
|
|
|
/**
|
* 是否忽略自定义的加密头
|
*/
|
private boolean isIgnoreSignHeader(Headers headers) {
|
String signHeader = headers.get(SmartHeader.IGNORE_SIGN_HEADER);
|
return !TextUtils.isEmpty(signHeader);
|
}
|
|
private JsonObject getBodyJson(Request request) {
|
RequestBody body = request.body();
|
if (body instanceof FormBody) {
|
JsonObject object = new JsonObject();
|
FormBody formBody = (FormBody) body;
|
for (int i = 0; i < formBody.size(); i++) {
|
object.addProperty(formBody.name(i), formBody.value(i));
|
}
|
return object;
|
} else {
|
//json格式
|
try {
|
String bodyString = getBodyString(request);
|
if (!TextUtils.isEmpty(bodyString)) {
|
final JsonElement parseString = JsonParser.parseString(bodyString);
|
return parseString.getAsJsonObject();
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
}
|
return null;
|
}
|
|
private String getBodyString(Request request) {
|
try {
|
RequestBody body = request.body();
|
if (body != null) {
|
Buffer buffer = new Buffer();
|
body.writeTo(buffer);
|
Charset charset = Charset.forName("UTF-8");
|
MediaType contentType = body.contentType();
|
charset = contentType.charset(charset);
|
return buffer.readString(charset);
|
}
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
return "";
|
}
|
|
|
|
|
|
private String jsonToUrlParameter(JsonObject object) {
|
final Map<String, String> map = GsonUtils.getGson().fromJson(object, new TypeToken<Map<String, String>>() {
|
}.getType());
|
final Uri.Builder builder = new Uri.Builder();
|
List<String> list = new ArrayList<>(map.keySet());
|
Collections.sort(list);
|
for (String key : list) {
|
String value = map.get(key);
|
if (valueNeedSign(value)) {
|
builder.appendQueryParameter(key, value);
|
}
|
}
|
return builder.build().getQuery();
|
}
|
|
|
/**
|
* 判断当前值是否需要参与签名,保持跟云端一致
|
* 空字符串不参与
|
* 数组,集合不参与
|
*
|
* @return ture 需要加密
|
*/
|
private static boolean valueNeedSign(String valueStr) {
|
try {
|
if (TextUtils.isEmpty(valueStr)) return false;
|
final char[] strChar = URLDecoder.decode(valueStr, "utf-8")
|
.substring(0, 1).toCharArray();
|
final char firstChar = strChar[0];
|
return firstChar != '{' && firstChar != '[';
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return false;
|
}
|
}
|