企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# **API架构** AWS 对每次API请求都进行一次完整的安全验证,验证处理过程与开发者选择的API技术协议有关(如选择HTTP或SOAP)。下图是一个抽象的API架构图: ![](images/screenshot_1574387757707.png) **请求处理过程** 1. 发起请求 2. 因安全或请求非法被拒绝 3. 调用AWS PaaS的本地接口封装 4. 将处理结果以JSON/XML文档返回 # **API接入方法** ## **1. HTTP(s) API接入** HTTP(s) API又叫Web API,开发者可以通过HTTP形式发起请求,获取JSON或XML的处理结果。由于HTTP被广泛的编程语言支持,开发者可以基于此HTTP形式与各种语言的企业应用进行交互。 在调用这类API之前,开发者需要向管理员申请API密钥,该秘钥由AWS CC的秘钥身份进行管理。包括访问凭证 ( access_key ) 和 私钥 ( secret )。 access_key将作为参数包含在每一个请求中发送,而secret负责生成请求串的签名,**secret需要妥善保管,请勿外传。** ### 1.1 技术规格 项|说明 --|-- 访问协议|HTTPS/HTTP 提交方式|POST/GET,推荐POST 业务参数|JSON 返回结果|JSON/XML 编码格式|UTF-8 ### **1.2 API请求结构** 项|说明 --|-- API入口|Portal URL + /openapi,例如:https://b2b.awspaas.com/openapi 公共参数|- cmd api名称(必须)<br>- access_key 访问凭证(必须)<br>- sig 请求消息的签名(必须),<b>详见下说明</b><br>- sig_method 签字算法,支持:HmacMD5<br>- format 处理结果数据格式。支持json和xml,默认为json<br>- timestamp 请求时间,long型毫秒值,默认和服务器事件不能超过6分钟 业务参数|一个json串,见相关API的说明文档 ### **1.3 API请求样例及接入说明** 一个典型的API请求如下所示,这是一个 app.install.check 的API请求 ``` https://b2b.awspaas.com/openapi ?timestamp=1439277618461 &sig_method=HmacMD5 &cmd=app.install.check &appId=com.actionsoft.apps.notification &access_key=Salesforce#1 &format=json &sig=DE90336BEDB0C3D3FE6DEE2FF0DF11AC ``` ### **1.4 API返回结构** 由请求参数format指定的数据格式,默认为json串。例如在Java客户端中,该参数运用如下: ``` //返回JSON结构 OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret); //或者 OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret, OpenApiClient.FORMAT_JSON); //返回XML结构 OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret, OpenApiClient.FORMAT_XML); ``` 项|说明 --|-- result|状态码。ok代表成功,error代表失败 errorCode|错误码 msg|结果信息。如果result值为error时,提供错误描述信息 data|业务数据 ### **1.5 API返回样例** 一个典型的API请求返回结果如下所示 这是一个 app.install.check API的JSON结果 ``` { "data" : true, "result" : "ok" } ``` 这是一个 app.install.check API的XML结果 ``` <?xml version="1.0" encoding="utf-8" standalone="yes"?> <boolResponse> <data>true</data> </boolResponse> ``` ### **1.6 接入调用说明** #### 1.获取秘钥 开发者在完成每次HTTP API调用前,API发起的URL中需要带上sig参数。sig参数是秘钥access_key和secret及参数串的签名。秘钥由AWSCC的秘钥身份进行管理,开发者可以向管理员申请API密钥,包括访问凭证 ( access_key ) 和 私钥 ( secret )。 ![](images/screenshot_1574387778727.png) #### 2.使用AWS HTTP SDK for Java API工具包(Java语言可使用此方法,其他语言见 第三点) 这是我们为Java开发者提供的HTTP API客户端开发工具包(AWS HTTP SDK for Java API工具包),可以简化对HTTP API的使用,也无需考虑URL签名过程。(依赖jar文件可在调用时联系管理员获取) jackson类库用于处理json到Java对象的转换处理。建议使用AWS PaaS平台默认提供的相关资源: ``` * webserver/webapps/portal/WEB-INF/lib/jackson-core-2.4.1.jar * webserver/webapps/portal/WEB-INF/lib/jackson-databind-2.4.1.jar * webserver/webapps/portal/WEB-INF/lib/jackson-module-jaxb-annotations-2.5.2.jar * webserver/webapps/portal/WEB-INF/lib/jackson-annotations-2.4.0.jar ``` ##### 2.1 JAVA客户端示例代码 **OpenApiClient构造函数** ``` //返回JSON结果 OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret,OpenApiClient.FORMAT_JSON); //返回XML结果 OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret,OpenApiClient.FORMAT_XML); //返回对象结果(不同API封装的结果对象不同,见示例代码) OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret); BoolResponse r = client.exec(apiMethod, args, BoolResponse.class); ``` **示例** ``` //API入口 String apiServer = "https://b2b.awspaas.com/openapi"; String accessKey = "Salesforce#1"; String secret = "0a799959-8327";//注意保密 String apiMethod = "bo.query";//API方法,cmd参数 //API请求参数 Map<String, Object> args = new HashMap<String, Object>(); args.put("boName","BO_ACT_TEST" ); //构建客户端 OpenApiClient client = new OpenApiClient(apiServer, accessKey, secret); //执行并获得查询结果 ListMapResponse r = client.exec(apiMethod, args, ListMapResponse.class); List bos = r.getData(); if (bos != null) { for(int i=0;i<bos.size();i++){ //... } } ``` #### 3.通过签名URL请求,完成API调用(其他语言) 签名的目标是由开发者在API客户端计算出系列参数组合的哈希值,将产生的信息添加到URL请求的sig参数。 ##### 3.1 获得秘钥 这里介绍API请求中签名 ( sig ) 的生成方法。签名需要开发者先在控制台创建API密钥 ,获得访问凭证 ( access_key ) 和私钥 ( secret ),这里我们假设 ``` access_key = 'Salesforce#1' secret = '0a799959-8327' ``` ##### 3.2 计算签名 例如API请求参数如下(这是一个 app.install.check API): ``` { "timestamp":"1439279383630", "sig_method":"HmacMD5", "cmd":"app.install.check", "appId":"com.actionsoft.apps.notification", "access_key":"Salesforce#1", "format":"json" } ``` ###### 1. 按参数名进行升序排列 准备参数。范围:cmd,access_key,timestamp,format,sig_method和业务参数(见API输入参数文档),其中不包括空值参数排序后的参数为: ``` { "access_key":"Salesforce#1", "appId":"com.actionsoft.apps.notification", "cmd":"app.install.check", "format":"json", "sig_method":"HmacMD5", "timestamp":"1439279383630" } ``` ###### 2. 构造签名串 以secret字符串开头,追加排序后参数名称和值,格式:secretkey1value1key2value2... 应用到上述示例得到签名串为(注意:签名串中间没有空格分割): ``` 0a799959-8327access_keySalesforce#1appIdcom.actionsoft.apps.notificationcmdapp.install.checkformatxmlsig_methodHmacMD5timestamp1439277618461 ``` ###### 3. 计算签名 计算被签名串加密的签名。将API密钥的私钥 (secret) 作为key,生成被签名串的 HmacMD5签名 将签名得到的16字节依次转化为大写的16进制字符串,如果字符串长度为1,在前补0,结果为32位字符串,例如:050CC7A1C04487EAE1197C31D28B7E37 ###### 4. 添加签名 将计算的签名值以sig参数名,附加到URL请求中。一个典型的API请求如下所示 这是一个 app.install.check 的API请求 ``` https://b2b.awspaas.com/openapi?timestamp=1439277618461 &sig_method=HmacMD5 &cmd=app.install.check &appId=com.actionsoft.apps.notification &access_key=Salesforce#1 &format=json &sig=DE90336BEDB0C3D3FE6DEE2FF0DF11AC ``` ## **2.SOAP API接入** SOAP API即Web Service。开发者可以通过HTTP传输协议发送SOAP格式的请求消息获得XML结构的处理结果。 在调用这类API之前,开发者需要向管理员申请API密钥,该秘钥由AWS CC的秘钥身份进行管理。包括用户名和密码及增强安全策略。 用户名和密码的传输需要遵循WS-Security的用户名密码类型令牌规范,**密码需要妥善保管,请勿外传**。 ### **2.1 技术规格** 项|说明 --|-- Transports|HTTPS/HTTP JSR|Java API for XML-Based Web Services (JAX-WS) 2.0 - JSR-224<br>Web Services Metadata for the Java Platform - JSR-181<br>SOAP with Attachments API for Java (SAAJ) - JSR-67 WS-*和相关规范|WS-I Basic Profile 1.1<br>WS-Reliable Messaging<br>WSDL 1.1<br>WS-Security<br>SOAP 1.1, SOAP 1.2<br>Message Transmission Optimization Mechanism (MTOM)<br>JAXB 2.x ### **2.2 API请求结构** 项|说明 --|-- API入口|Portal URL + /openapi,例如:https://b2b.awspaas.com/openapi 查询参数|- service 值为服务ID(必须),例如appApi<br>- wsdl true/false,是否返回WSDL(可选) 业务参数|一个json串,见相关API的说明文档 ### **2.3 API请求样例及接入说明** 一个典型的API请求如下所示,这是一个 isInstalled 的SOAP API请求 ``` <soap:Envelope xmlns:ser="http://service.sdk.actionsoft.com/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"/> <soap:Body> <ser:isInstalled> <appId>com.actionsoft.apps.notification</appId> </ser:isInstalled> </soap:Body> </soap:Envelope> ``` ### **2.4 API返回结构:** 项|说明 --|-- result|状态码。ok代表成功,error代表失败 errorCode|错误码 msg|结果信息。如果result值为error时,提供错误描述信息 data|业务数据 ### **2.5 API返回样例** 一个典型的SOAP API请求返回结果如下所示 这是一个 isInstalled 的SOAP API服务返回结果 ``` <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns1:isInstalledResponse xmlns:ns1="http://service.sdk.actionsoft.com/"> <return xmlns:ns2="http://service.sdk.actionsoft.com/"> <data>true</data> </return> </ns1:isInstalledResponse> </soap:Body> </soap:Envelope> ``` ### **2.6 接入调用说明** #### 1.获取秘钥 秘钥由AWS CC的秘钥身份进行管理,开发者可以向管理员申请API密钥,包括用户名和密码。 ![image](DFA9D6CE13EE4B9485E309040650D825) #### 2.使用SoapUI工具调用 SoapUI是一个开源测试工具,希望快速熟悉SOAPAPI的开发者,也可以使用这个客户端测试每个API。 **场景** 调用appApi服务的isInstalled方法判断AWS PaaS是否安装了某个应用。假定SOAP安全策略配置为用户名密码认证、密码加密传输 ``` 用户名:Salesforce#1 密码:0a799959-8327 ``` **步骤** **1.创建soapUI工程,File > new soapUI Project** ![](images/screenshot_1574387806573.png) **2.配置参数及认证用户名密码** ![](images/screenshot_1574387811697.png) ![](images/screenshot_1574387816728.png) **3.运行查看结果** ![](images/screenshot_1574387822705.png) #### 3.使用CXF客户端调用 **场景** 调用appApi服务的isInstalled方法判断AWS PaaS是否安装了某个应用。假定服务端配置用户名密码认证、密码加密传输 ``` 用户名:Salesforce#1 密码:0a799959-8327 ``` **完整的CXF示例代码** ``` import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import org.apache.ws.security.WSConstants; import org.apache.ws.security.WSPasswordCallback; import org.apache.ws.security.handler.WSHandlerConstants; import com.actionsoft.sdk.service.AppApi; import com.actionsoft.sdk.service.AppApiPortType; import com.actionsoft.sdk.service.BoolResponse; public class AppApiClient { public static void main(String[] args) { // 构造拦截器,设置用户名密码属性和认证类型 Map<String, Object> outProps = new HashMap<String, Object>(); outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); //outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);//密码明文还是密文,不设置时默认密文 outProps.put(WSHandlerConstants.USER, "Salesforce#1"); outProps.put(WSHandlerConstants.PW_CALLBACK_REF, new UTSetPasswordCallback()); WSS4JOutInterceptor interceptor = new WSS4JOutInterceptor(outProps); // 注入cxf的拦截器增加用户名密码 AppApi api = new AppApi(); AppApiPortType port = api.getAppApiPort(); Client client = ClientProxy.getClient(port); client.getOutInterceptors().add(interceptor); // 服务方法调用 BoolResponse r = port.isInstalled("com.actionsoft.apps.notification"); // 业务异常判断 if (r.getErrorCode() == null) { System.out.println(r.isData()); } else { System.out.println(r.getErrorCode() + "," + r.getMsg()); } } private static class UTSetPasswordCallback implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; if ("Salesforce#1".equals(pc.getIdentifier())) { pc.setPassword("0a799959-8327"); return; } } } } } ``` **Simple Frontend Client Proxy(CXF私有调用方式)** ``` import org.apache.cxf.frontend.ClientProxyFactoryBean; ... ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); factory.setServiceClass(AppApiPortType.class); factory.setAddress("http://localhost:8088/portal/r/s?service=appApi"); AppApiPortType client = (AppApiPortType) factory.create(); ``` #### 4. 使用JDK自带WebService框架 **注意:** 1. JDK1.6或更高版本才提供Web Service实现。 2. 目前JDK对WS-*规范的支持不够完善,例如发送WS-Security规范要求的用户名密码时需要借助其它服务框架,因此本章没有安全验证。(AWS PaaS提供的官方SOAP API要求必须有用户名密码验证,因此本章节调用方式不支持由AWS PaaS提供的官方SOAP API) **JAX-WS Proxy方式调用服务步骤** 1. 准备JDK1.6或以上版本 2. 生成服务客户端文件 使用JDK bin目录下的wsimport命令生成服务客户端文件,如果不指定。示例: ``` wsimport -keep -clientjar app_service_client.jar "http://localhost:8088/portal/r/s?service=appApi&wsdl=true" ``` 3. 获得服务和代理对象 在生成的app_service_client.jar中有2个重要的类,如下: 项|说明 --|-- AppApi|AppApi是服务类,继承javax.xml.ws.Service,它的名字默认和wsdl中服务名称对应,wsdl:service的name属性,该类用于创建服务对象实例 AppApiPortType|AppApiPortType类是该服务的SEI(service endpoint interface),可以得到代理对象实例 AppApi的构造函数中可以指定3个参数: 项|说明 --|-- java.net.URL wsdlDocumentLocation|WSDL路径,默认使用app_service_client.jar中备份的生成源WSDL QName serviceName | 该参数指定调用哪个服务 WebServiceFeature... features | 服务的特殊功能或者处理,例如MTOMFeature可以指定是否优化附件传输 通过生成的服务类获得代理对象的代码示例: ``` AppApi api = new AppApi(); AppApiPortType port = api.getAppApiPort(); ``` 通过javax.xml.ws.Service和SEI得到代理对象: ``` URL wsdlURL = new URL("http://localhost:8088/portal/r/s?service=appApi&wsdl=true"); QName SERVICE_NAME = new QName("http://service.sdk.actionsoft.com/", "AppApi"); Service service = Service.create(wsdlURL, SERVICE_NAME); AppApiPortType client = service.getPort(AppApiPortType.class); ``` 4. 通过代理对象调用服务 ``` AppApiPortType client = service.getPort(AppApiPortType.class); BoolResponse result = client.isInstalled("com.actionsoft.apps.notification"); ``` **JAX-WS Dispatch方式调用服务步骤** 1. 准备JDK1.6或以上版本 2. 获得服务和Dispatch对象 3. 通过Dispatch对象调用服务 ``` import java.net.URL; import javax.xml.transform.Source; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; ... URL wsdlURL = new URL("http://localhost:8088/portal/r/s?service=appApi&wsdl=true"); Service service = Service.create(wsdlURL, new QName("http://service.sdk.actionsoft.com/", "AppApi")); Dispatch<Source> disp = service.createDispatch( new QName("http://service.sdk.actionsoft.com/", "AppApiPort"), Source.class, Service.Mode.PAYLOAD); Source request = new StreamSource("<appId>com.actionsoft.apps.notification</appId>") Source response = disp.invoke(request); ```