APP通信加密方案

来源:互联网 发布:闰年判断方法 c语言 编辑:程序博客网 时间:2024/05/22 08:29


 

 

App版接口与pc版接口的区别:

App版:每次请求都需要携带 appId参数(针对所有接口:登录、未登录接口),所有请求都会经过加密签名校验流程,数据 HTTP / HTTPS加密传输。

 

Pc版:每次请求无需登录的接口没有参数限制要求,需登录的接口必须传userId、token,token为草根金融后台生成,与XX平台的token无关,数据传输为明文。

 

共同点:两个版本的接口只在mvc层不同,业务逻辑代码为同一套。所有接口均为无状态,网页端、app端需根据接口返回的结果判断用户当前是否登录。所有请求都要带上 accessFrom 参数

 

 

App端通信流程详解:

从上至下,按环节说明:

 

1.        判断appId、appSecret是否存在

appId:

app设备的唯一标识符,由服务端生成,app每次发送请求时,都需要带上此参数。

 

appSecret

当前设备的通信私钥,由服务端生成

 

app端需要同时缓存 appId 、appSecret两个字段,appId、appSecret在服务端会有过期时间,2 种情况下需求重新获取:

一、 服务端返回 secret_pass_time_error字符串时,app端在得知私钥过期,此时需要重新获取并缓存。

二、 App刚启动时

 

 

2.        发送请求生成 appId 、appSecret

接口地址:

/XXXX/secret_key/generate.json

返回值:

{"data":{"appId":"0c008f12901c4cd2a689635b8f6de0eepe9il7g0e27hfmir","appSecret":"f9f731c1cfc04bc48cd1b9b631709949"},"success":true}

请求成功后,app端需缓存appId、appSecret,并在以后的请求中始终带上appId字段。

 

注:

在调用该接口时,由于appSecret未生成,所有全程使用公钥加密,并且在以后其他接口调用中,对于  appId字段,统一使用公钥加密、解密。

 

 

3.        加密签名过程

加密算法

Aes + base64

 

Javaapp端代码示例:

 

 

// 用于保存请求的参数名

List<String> keys = newArrayList<String>(param.size() + 1);

// 最终发送到服务器的参数键值对

Map<String, String> requestMap =new HashMap<String,String>();

if (appId !=null) {

    requestMap.put(AppIdKey,appId);

    keys.add(AppIdKey);

}

 

/** 加密业务参数(私钥) */

for (Iterator<String>it =param.keySet().iterator();it.hasNext();) {

    String paramKey = it.next();

    // 不对appId进行私钥加密

    if (paramKey.equals(AppIdKey)) {

        continue;

    }

    keys.add(paramKey);

    String encodeValue = EncryptUtil.aesEncode(param.get(paramKey),appSecret);

    requestMap.put(paramKey,encodeValue);

}

 

/** md5签名(私钥) */

// 先对参数名正序排序

Collections.sort(keys);

StringBuilder sb = new StringBuilder();

for (String key : keys) {

    // 所有参数值相加

    sb.append(requestMap.get(key));

}

// 最后加上私钥

sb.append(appSecret);

requestMap.put("sign", Md5Encrypt.md5(sb.toString()));

 

/** 全局加密(公钥)(包含已用私钥加密过的参数值、未加密的参数名以及appId */

Map<String, String> encrptyParam =new HashMap<String,String>();

for (Map.Entry<String, String>entry :requestMap.entrySet()) {

    encrptyParam.put(EncryptUtil.aesEncode(entry.getKey(),publicSecret), EncryptUtil.aesEncode(entry.getValue(),publicSecret));

}

 

/** 发送请求 */

String result = HttpRequestUtil.httpPostAccess(ApiAddress +uri,encrptyParam,"utf-8");

 

/** 缓存的appSecret过期,需求重新生成appIdappSecret后再发请求 */

if ("secret_pass_time_error".equals(result)) {

    throw new AppScretTimeOutException("密钥过期");

}

 

/* 解密响应数据(私钥) */

result = EncryptUtil.aesDecode(result,appSecret);

 

 

 

 

 

 

 

0 0
原创粉丝点击