New file |
| | |
| | | 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")); |
| | | } |
| | | |
| | | } |