hxb
2024-10-24 d723fee177238df0dbab80eb788876ebd154927d
HDLLinkPMSdk/src/main/java/com/hdl/linkpm/sdk/core/interceptor/HDLEncryptInterceptor.java
New file
@@ -0,0 +1,235 @@
package com.hdl.linkpm.sdk.core.interceptor;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import com.hdl.hdlhttp.utils.GsonConvert;
import com.hdl.linkpm.sdk.HDLLinkPMSdk;
import com.hdl.linkpm.sdk.core.interceptor.HDLSmartHeader;
import com.hdl.linkpm.sdk.template.GsonUtils;
import com.hdl.linkpm.sdk.utils.HDLMD5Utils;
import com.hdl.linkpm.sdk.utils.HDLSDKLog;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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 HDLEncryptInterceptor 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 = HDLLinkPMSdk.getAppKey();
        final String appSecret = HDLLinkPMSdk.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;
    }
    /**
     * 是否忽略自定义的加密头
     */
    private boolean isIgnoreSignHeader(Headers headers) {
        String signHeader = headers.get(HDLSmartHeader.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.encodedName(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 "";
    }
    /**
     * 需要按字母排序
     *
     * @param json 所有字段使用urlParameter拼接,除了appSecret
     */
    private String getSign(JsonObject json, String appSecret) {
        String builder = jsonToUrlParameter(json) +
                appSecret;
        return HDLMD5Utils.encodeMD5(builder);
    }
    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();
        final Uri.Builder builder = new Uri.Builder();
        try {
            JSONObject jsonobject = JSON.parseObject(object.toString());
            List<String> list = new ArrayList<>(jsonobject.keySet());
            Collections.sort(list);
            for (String key : list) {
                Object obj = jsonobject.get(key);
                if (isSignValue(obj))
                    builder.appendQueryParameter(key, obj.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return builder.build().getQuery();
    }
    private static boolean isSignValue(Object value) {
        if (value == null) return false;
        if (value instanceof Number) return true;
        String className = value.getClass().getSimpleName();
        switch (className) {
            case "String":
            case "Integer":
            case "Boolean":
            case "Long":
            case "Short":
            case "Float":
            case "Double":
            case "Character":
            case "Byte":
                if (TextUtils.isEmpty(value.toString())) return false;
                return true;
            default:
                return false;
        }
    }
    /**
     * 基本类型加密
     * <p>
     * 判断当前值是否需要参与签名,保持跟云端一致
     * 空字符串不参与
     * 数组,集合不参与
     *
     * @return ture 需要加密
     */
    private static boolean valueNeedSign(String valueStr) {
        try {
            if (!TextUtils.isEmpty(valueStr)) {
                JsonElement json = JsonParser.parseString(valueStr);
                if (json != null && (json.isJsonPrimitive() || json.getAsJsonPrimitive().isString())) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    public static boolean isPrimitive(String type) {
        return (type.equals("char")
                || type.equals("double") || type.equals("float")
                || type.equals("integer") || type.equals("string")
                || type.equals("boolean")) || (type.equals("Char")
                || type.equals("Double") || type.equals("Float")
                || type.equals("Integer") || type.equals("String")
                || type.equals("Boolean") || type.equals("int")
                || type.equals("long") || type.equals("Int") || type
                .equals("Long"));
    }
}