## 一、概述
提供外部自建系统的代理商,可以通过接口服务,实现对方系统与我方系统之间的技术衔接;
![](https://img.kancloud.cn/d1/f7/d1f765bbc1d73f1b7fe491041d3fa223_620x254.png)
## 二、参考
>[danger]
> 1、在本系统里面,无需独立的去开放平台开户,创建顶级代理商的时候,就自动开户了,也就可以获得相关参数了;
> 2、需要注意,需要在开放服务模块,针对当前代理商的客户端,设置允许访问的IP白名单;
> 3、调用的api,需要对客户端做授权;
## 三、整体流程
创建接口开放服务账号->获取接口开放服务参数->第三方编写程序->测试->上线;
![](https://img.kancloud.cn/e8/f4/e8f4ede4edf86d551ce2552963863458_1173x168.png)
### **客户端请求实例代码**
```
public class ClientSample
{
public static void main(String[] args)
{
Log4jV2Util.initLog4jV2TestEnv();
String hostUrl = "http://{hosturl}/api/rayoauth";
String apiUrl = "/query/card";
String appId = "ray40c9903c1";
String appSecret = "46bacebf-f63c-41cc-b29c-5812994a5e83";
Map<String, String> paramap = new HashMap();
paramap.put("userCode", "13313312");
String result = OauthCaller.call(hostUrl, apiUrl, appId, appSecret, paramap);
Logger logger = LoggerFactory.getLogger(OauthClientTest.class);
logger.debug(result);
}
}
```
OauthCaller:
```
public class OauthCaller
{
public static String call(String oauthHostUrl, String servceUrl, String appId, String appSecret, Map<String, String> businessParaMap)
{
Map<String, String> allParaMap = new HashMap();
Map<String, String> headmap = new HashMap();
headmap.put(RayOauthServerConstants.rayOauthHeadAppId, appId);
headmap.put(RayOauthServerConstants.rayOauthHeadTimeStamp, String.valueOf(new Date().getTime()));
allParaMap.putAll(businessParaMap);
allParaMap.putAll(headmap);
headmap.put(RayOauthServerConstants.rayOauthHeadSignature, Sign.generateSign(allParaMap, appSecret));
String result = null;
try
{
result = HttpPostUtil.executeActionWithHead(oauthHostUrl + servceUrl, businessParaMap, headmap, "", false);
}
catch (Exception e)
{
e.printStackTrace();
}
return result;
}
}
```
HttpPostUtil.executeActionWithHead:
```
public static String executeActionWithHead(String postUrl, Map<String, String> postParaMap, Map<String, String> headParaMap, String paraContentType, boolean trace) throws Exception
{
BasicCookieStore cookieStore = new BasicCookieStore();
try (final CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(connectionConfig()).setDefaultCookieStore(cookieStore).setDefaultRequestConfig(requestConfig()).build();)
{
String result = null;
try
{
ClassicRequestBuilder requestBuilder = ClassicRequestBuilder.post().setUri(postUrl);
if (postParaMap != null)
{
Iterator paramIterator = postParaMap.entrySet().iterator();
while (paramIterator.hasNext())
{
Map.Entry entry = (Map.Entry) paramIterator.next();
requestBuilder.addParameter(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
}
}
if (headParaMap != null)
{
Iterator headIterator = headParaMap.entrySet().iterator();
while (headIterator.hasNext())
{
Map.Entry<String, String> entry = (Map.Entry) headIterator.next();
requestBuilder.addHeader(entry.getKey(), entry.getValue());
}
}
if (!StringUtils.isEmpty(paraContentType))
{
requestBuilder.setHeader("Content-type", paraContentType);
}
ClassicHttpRequest request = requestBuilder.build();
try (final CloseableHttpResponse response = httpclient.execute(request))
{
result = EntityUtils.toString(response.getEntity());
}
}
catch (Exception ex)
{
logger.error("executeAction执行中发生了异常,堆栈如下:", ex);
}
return result;
}
}
```
## 四、技术要求
1.所有接口的请求,采用httpPost方式提交,发出http请求的时候,请求content-type需设定为:application/x-www-form-urlencoded;charset=UTF-8 ,参数按照普通表单参数传值,不必包裹成一个json字符串;
2.所有接口的响应,采用json格式,编码为UTF-8,响应的content-type为:application/json;charset=UTF-8);
3.提供ip白名单功能,仅供授权的ip调用;
4.每个对外提供服务的api,都必须在请求头部包含参数rayOauthServerAppId及rayOauthServerTimeStamp,为了确保不被外部不法分子恶意篡改请求,请求参数中绝对不能包含appSecret;
5.每个对外提供服务的api,都必须在请求头部包含一个rayOauthServerSignature参数,该参数是通过算法计算出来的值,具体算法参考后续签名算法章节;
6.考虑服务器承载量,目前限制每个ip访问接口频率不得超过1秒10次,超过这个次数,该ip将会被禁止调用,程序中不得做高频率轮询;
## 五、时间戳格式
1.获取从1970, 00:00:00开始到当前的毫秒数(13位) ;
2.每个api请求的有效时间为3分钟,所以,务必确保当前服务请求的时间是准确的;
## 六、rayOauthServerSignature签名算法
假设:rayOauthServerSignature= 当前api的所有参数(除rayOauthServerSignature外),根据 **参数名升序** 排序,以“**`参数名=值&`**”的方式连接起来,最后一个参数不需要&符号,以值结尾;
结果:rayOauthServerSignature= md5(md5(paramstrings)+appSecret)
> 注意:
> 1、是双层md5(32位小写)加密,中间那个"+"仅表示两段字符相连,并不包括该符号本身;
> 2、参数包括了请求头和请求体里面的所有参数;
## 七、测试案例
![](https://img.kancloud.cn/16/73/1673519b3f79c1ba8adb9b48b25c4dcc_1323x692.png)![](https://img.kancloud.cn/1c/8d/1c8d82217a7b0a8694b480acaf6296ad_1371x703.png)