Android Okhttp 拦截器中加密 请求体 (DES加密解密)

593 阅读4分钟

最近公司为了项目安全 使用了https 所有接口要使用DES 加密 加密 RequestBody 的value值

心想 这不是很简单吗 直接在拦截器中获取到要上传的数据 然后加密 重新赋值 很简单嘛 但是实践起来 我真的气的想要骂娘 太坑了好吗。。。。无语直接就打到我的脸上

废话不多说 让我重温一下这些坑

第一步 在网络请求类里添加拦截器

在拦截器里对上传的数据进行操作

如果是post 请求 取出来request.body(); 循环 取出 encodedValue 加密后 重新再 addEncoded 添加进去 这里要注意 URLDecoder的解码

如果是get请求 先拿到 request.url() 然后再看这个url中包含不包含请求参数 url.encodedQuery() 如果这个不为空的话 就是接下来字符串截取->修改加密->重新拼接

然后进行网络请求

然后解密 ---->

和后台商量后 后台返回的数据只对 “data” 字段的value进行了加密 好 那我只对“data” 进行解密就好了

获取到 response 对返回的json进行解析 因为后台对“data”进行加密 无疑 data是String类型的 解析解密后 怎么将解密后的data重新安装到json中呢 ?

解密后的data是String类型的 但是原本想要表达的 “data” 该是什么类型呢 不知道什么类型 又该怎么准确的安到实体类里呢

我被这个“data”困阻了 一直在想 怎么直接去操作json串 我知道这也不是一个绝美精妙的办法 但是我脑容量毕竟不大 我觉得我能想到解决的办法已经很棒了 substring(0,1);毕竟 返回的json也就那么几种 { 、[ 、还有什么都没有的

那不就好办了吗 直接统称两类 jsonArray 和jsonObject 至此 我才终于有了完整的思路

我猜看到这里大家也到了耐心的极限了 但是整体的思路 使用的方法 上面已经基本都讲的差不多了 合格的程序员 应该脑海里也知道该怎么做了 有点凡尔赛那味了

上代码!!!!

public class OkhttpInstance {

private static OkHttpClient okHttpClient;
private static Response response;

public static synchronized OkHttpClient createInstance() {
    if (okHttpClient == null) {
        synchronized (OkhttpInstance.class) {
            if (okHttpClient == null) {
                okHttpClient = new OkHttpClient.Builder()
                        .connectTimeout(60, TimeUnit.SECONDS)      //设置连接超时
                        .readTimeout(60, TimeUnit.SECONDS)         //设置读超时
                        .writeTimeout(60, TimeUnit.SECONDS)        //设置写超时
                        .retryOnConnectionFailure(true)            //是否自动重连
                        .addInterceptor(interceptor)  //添加拦截器
                        .build();
            }
        }
    }
    return okHttpClient;
}

private static Interceptor interceptor = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Request.Builder requestBuilder = request.newBuilder();

        //post请求加密
        if (request.body() instanceof FormBody) {
            FormBody.Builder newFormBody = new FormBody.Builder();//创建新表单
            FormBody oidFormBody = (FormBody) request.body();//请求表单
            //循环取出 request Body 注意FormBody 才会有size属性 FormBody可以满足大部分的请求
            for (int i = 0; i < oidFormBody.size(); i++) {
                String str = oidFormBody.encodedValue(i);//value
                String decode = URLDecoder.decode(str);//对value进行URLDecoder解码
                String s = oidFormBody.encodedName(i);//name
                String name = URLDecoder.decode(s);//对name进行URLDecoder解码 很重要 这两个都加上 不然取出请求体的时候有的请求体被URLDecoder编码 后台不知道你传过去的是什么 
                String encrypt = DesCipherUtil.encrypt(decode, HDUrl.PAS);//des加密 HDUrl.PAS 是我的密码 你跟后台商量定什么为密码
                newFormBody.addEncoded(name.trim(), encrypt.trim());//去空格 相当重要!!都是我踩过的坑
            }
            requestBuilder.method(request.method(), newFormBody.build());
        }

        request = requestBuilder.build();

// get请求加密 //还回加密的请求头 HttpUrl url = request.url(); String path = url.encodedPath();// String query = url.encodedQuery();//请求参数 if (!TextUtils.isEmpty(query)) {

            StringBuffer sb = new StringBuffer();
            sb.append(HDUrl.DEFAULT).append(path).append("?");//HDUrl.DEFAULT是我的请求地址:https://192.16.2.88 我猜你知道我说的是什么
            Set<String> queryList = url.queryParameterNames();
            Iterator<String> iterator = queryList.iterator();
            for (int i = 0; i < queryList.size(); i++) {

                String queryName = iterator.next();
                sb.append(queryName).append("=");
                String queryKey = url.queryParameter(queryName);
                //对query的key进行加密
                if (TextUtils.isEmpty(queryKey) || null == queryKey || "null".equals(queryKey) || queryKey.length() == 0 || "".equals(queryKey)) {
                } else {
                    Log.e("tag", "queryKey-----------" + queryKey);
                    sb.append(DesCipherUtil.encrypt(queryKey, HDUrl.PAS));
                }
                if (iterator.hasNext()) {
                    sb.append("&");
                }
            }
            String newUrl = sb.toString();

// 进行加密后的get请求链接 Request.Builder url1 = request.newBuilder() .url(newUrl); request = url1.build();

        }
        response = chain.proceed(request);
        byte[] data = response.body().bytes();
        String s = new String(data);
        MediaType mediaType = response.body().contentType();
        try {
            Log.e("tag", "s-----------------------" + s);
            JSONObject jsonObject = new JSONObject(s);
            int code = 0;
            if (jsonObject.has("code")) {
                code = jsonObject.getInt("code");
            } else {
                code = jsonObject.getInt("errCode");
            }
            if (code == 200 || code == 0) {

// 当code=200/0时解密 if (jsonObject.has("data")) { String code1 = jsonObject.getString("data"); String decrypt = DesCipherUtil.decrypt(code1, HDUrl.PAS); jsonObject.remove("data"); jsonObject.put("data", decrypt); Gson gson = new Gson(); // DefaultBean defaultBean = gson.fromJson(s, DefaultBean.class); if (decrypt.substring(0, 1).equals("[")) { List arrData = gson.fromJson(decrypt, new TypeToken<List>() { }.getType()); defaultBean.setData(arrData); } else if (decrypt.substring(0, 1).equals("{")) { Object objectData = gson.fromJson(decrypt, Object.class); defaultBean.setData(objectData); } else { defaultBean.setData(decrypt); } s = new Gson().toJson(defaultBean); }

            } else if (code == 10100) {
                //就代表token过期了
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Looper.prepare();
                        UserInfo userInfo = (UserInfo) ShareprefencesUtils.getBean(App.getApplicationContent(), ShareprefencesUtils.USER_INFO);
                        userInfo.setAccess_token("");
                        ShareprefencesUtils.putBean(App.getApplicationContent(), ShareprefencesUtils.USER_INFO, userInfo);
                        Intent intent = new Intent(App.getApplicationContent(), SelectJoinActivity.class)
                                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                        App.getApplicationContent().startActivity(intent);
                        Toast.makeText(App.getApplicationContent(), "登录超时请重新登录", Toast.LENGTH_SHORT).show();
                        Looper.loop();
                    }
                });
                thread.start();
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return response.newBuilder()
                .body(ResponseBody.create(mediaType, s))
                .build();
    }
};

public static synchronized OkHttpClient getInstance() {
    return okHttpClient;
}

其实已经很容易看懂了 一些东西我就不做解释了 自己悟去吧 下面贴一下DES加密解密类

private DesCipherUtil() { throw new AssertionError("No DesCipherUtil instances for you!"); }

static {
    // add BC provider

// Security.addProvider(new BouncyCastleProvider()); }

/**
 * 加密
 * 
 * @param encryptText 需要加密的信息
 * @param key 加密密钥
 * @return 加密后Base64编码的字符串
 */
@SuppressLint("NewApi")
public static String encrypt(String encryptText, String key) {

    if (encryptText == null || key == null) {
        throw new IllegalArgumentException("encryptText or key must not be null");
    }

    try {
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] bytes = cipher.doFinal(encryptText.getBytes(Charset.forName("UTF-8")));
        return Base64.getEncoder().encodeToString(bytes);

    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException
        | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) {
        throw new RuntimeException("encrypt failed", e);
    }

}

/**
 * 解密
 * 
 * @param decryptText 需要解密的信息
 * @param key 解密密钥,经过Base64编码
 * @return 解密后的字符串
 */
public static  String decrypt(String decryptText, String key) {

    if (decryptText == null || key == null) {
        throw new IllegalArgumentException("decryptText or key must not be null");
    }

    try {
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] bytes = new byte[0];
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            bytes = cipher.doFinal(Base64.getDecoder().decode(decryptText));
        }
        return new String(bytes, Charset.forName("UTF-8"));

    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException
        | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) {
        throw new RuntimeException("decrypt failed", e);
    }
}
public static void main(String[] args) {

}

这些都是我实实在在用到项目中的 有问题别质疑 我的代码没有问题 傲娇脸