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 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 = HDLLink.getInstance().getAppKey(); final String appSecret = HDLLink.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 map = GsonUtils.getGson().fromJson(object, new TypeToken>() { }.getType()); final Uri.Builder builder = new Uri.Builder(); List 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; } }