调用部署在 MindSphere 中的 app 暴露的 APIs
目录:1. Cloud Foundry App1.1. Session1.1.1. JS 代码调用示例1.1.2. 通过第三方工具 postman 调用测试验证 API1.2. User Token1.3. Technical User1.4. App Credential1.4.1. 应用凭证介绍1.4.2. APP 与 Token Management Service 置换token1.4.3
function testData() {
var apiReq = null;
if (typeof (XMLHttpRequest) != undefined) {
apiReq = new XMLHttpRequest();
} else {
apiReq = new ActiveXObject("Microsoft.XMLHttp");
}
var url = "/api/datasource-supplab/v1/updateValue";
//var apiReq = new XMLHttpRequest();
apiReq.withCredentials = true;
var xtoken = getCookie("XSRF-TOKEN");
console.log('come from cookie XSRF-TOKEN:' + xtoken);
var ss = getCookie("SESSION");
var sessin = "SESSION=" + ss + ";" + "XSRF-TOKEN=" + xtoken;
apiReq.open("post", url, false);// 'false' makes the request synchronous
apiReq.setRequestHeader("X-XSRF-TOKEN", xtoken);
apiReq.setRequestHeader("Cookie", sessin);
apiReq.onreadystatechange = function () {
if (apiReq.readyState === 4) { // When readyState property is 4 and status property is 200,
the response is ready
if (apiReq.status === 200) {
console.log('POST API response:' + apiReq.response);
document.getElementById("response_api_value").innerHTML = "POST API response:
" + apiReq.response;
} else {
console.error('Request status text:' + apiReq.statusText);
}
}
}
console.log('POST:' + url);
apiReq.send(null);
}
function getCookie(name) {
var strcookie = document.cookie;//获取 cookie 字符串
var arrcookie = strcookie.split(";");//分割
//遍历匹配
for (var i = 0;i < arrcookie.length;i++) {
var arr = arrcookie[i].split("=");
if (arr[0] == name) {
return arr[1];
}
}
return null;
}
function callGetApi() {
var apiReq = null;
if (typeof (XMLHttpRequest) != undefined) {
apiReq = new XMLHttpRequest(); } else {
apiReq = new ActiveXObject("Microsoft.XMLHttp"); }
var url = "/api/datasource-supplab/v1/getValue"
apiReq.open("get", url, false);// 'false' makes the request synchronous
apiReq.onreadystatechange = function () {
if (apiReq.readyState === 4) { // When readyState property is 4 and status property is 200,
the response is ready
if (apiReq.status === 200) {
console.log('Get API response:' + apiReq.response);
document.getElementById("response_api_value").innerHTML = "GET API response: " + apiReq.response; } else {
console.error('Request status text:' + apiReq.statusText); } } }
console.log('GET:' + url);
apiReq.send(null); }
Postman 调用将 https://supplab-callpostappapi-supplab.cn1.mindsphere-in.cn/api/datasource-supplab/v1/updateValue 接口地址复制到 postman 地址栏中, 将 cockie 和 X-XSRF-TOKEN 添加到 headers 中, 从 cockie 中取出 XSRF-TOKEN 值和SESSION 值添加到 headers 中设置 Cockie 参数值和 X-XSRF-TOKEN 参数值{X-XSRF-TOKEN:XSRF-TOKEN};{Cockie:SESSION=SESSION 值;XSRF-TOKEN =XSRF-TOKEN 值}如
GET 方法在 postman 中调用方法和 POST 调用方法差不多都需要在 header 中添加参数, 这里可以不用在 header 添加 X-XSRF-TOKEN 值只需要设置 Cockie 值即可, postman 调用将 https://supplab-callpostappapi-supplab.cn1.mindsphere-in.cn/api/datasource-supplab/v1/getValue 接口地址复制到 postman 地址栏中, 从 cockie 中取出 XSRF-TOKEN 值和 SESSION 值添加到 headers 中, 设置 Cockie {Cockie:SESSION=SESSION 值;XSRF-TOKEN =XSRF-TOKEN 值}如
1.2. User Token
这里的 User token 指的是从 MindShpere 平台中, RequestHeader 中获的 Authorization 的值, Authorization 是在后端程序在实现过程从 RequestHeader 中获取, 我们一般称呼它为 User Token. 利用这个 user token 可以去访问 MindSphere 平台提供 api 和已经注册 app 的 api. 获取 user token 的 Java 代码示例:
@RequestMapping("/getAccessToken")
public String getAccessToken(@RequestHeader("Authorization") String userToken) throws IOException,
MindsphereException {
return userToken; }
- 利用 user token 访问 MindSphere 的 api, 要使 user token 能够访问 MindSphere api, 必须在 DeveloperCockpit 的授权管理中, 给 app 添加访问 MindSphere api 的相关服务角色(Role), 如要使 user token 能够访问 time series service 提供 api 读写数据, 就必须给 APP 添加 mdsp:core:iot.timAdmin 的角色, 如下图所示:
- 通过代码实现利用 User Token 访问 MindSphere api 接口格式:https://gateway.cn1.mindsphere-in.cn/{服务相关的 api} 如:https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_model
@RequestMapping("/getAccessTokenValue")
public String getAccessTokenValue(@RequestHeader("Authorization") String token) throws
IOException, MindsphereException {
HttpHeaders headers = new HttpHeaders();
headers.set("cache-control", "no-cache");
headers.set("Content-Type", "application/json");
headers.add("Authorization", token);
RestTemplate restTemplate = new RestTemplate();
String url = "https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_model";
String bodyJson = "";
HttpEntity<String> requestEntity = new HttpEntity<String>(bodyJson, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET,
requestEntity, String.class);
String responseBody = responseEntity.getBody().toString();
System.out.println("responser body:" + responseBody);
return responseBody; }
- 通过 postman 访问 MindSphere api, 在 postman 中地址栏中输入 https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_mode, 然后选择 Auth->type->bearer Token, 然后在 Token 中输入 uesrtoken, 点击发送
2. 利用 user token 访问 自己开发 app 的 api, 这个方法主要用来验证 app 提供 api, 一般后端程序可以直接获取利用 usertoken 去访问相关的资源, 除非两个后台 app 之间的交互, 这样的情况, 要先获取被访问 app 的 user token
- 访问格式 https://gateway.cn1.mindsphere-in.cn /api/{app 名称} -{租户名称}/{版本信息}/{app 接口地址};如 https://gateway.cn1.mindsphere-in.cn/api/datasource-supplab/v1/getValue
- 利用 user token 通过 postman 访问 app api, 在 postman 中地址栏中输入 https://gateway.cn1.mindspherein.cn/api/datasource-supplab/v1/getValue, 然后选择 Auth->type->bearer Token, headers 中设置{ key: Content-Type ;Value:application/json } 然后在 Token 中输入 uesrtoken, 点击发送
3. 可以 https://jwt.io/网址中输入 Authorzation 的 token 可以查看 token 可以访问接口的权限, 如图所示
1.3. Technical User
Service credential(租户服务凭证信息). 一般只有开发者账号才有权限申请, 当您购买了 MindSphere 开发者账号时, 就可以创建工单提交工单, 申请开通服务凭证, 具体申请格式可以查看链接中的 https://developer.mindsphere.io/zh/howto/howtoselfhosted-api-access.html 创建服务凭证内容, 申请的开发者账号(tenant name)服务凭证包括两个内容 client_id 和 client _secret, 我们将开通租房凭证获取的 client_id 和 client_secret 称为 Tech user, 使用 tech user 信息与 MindSphere
平台交互获取 token, 然后应用 token 访问 MindSphere 平台的提供所有 api, 这个 token 的有效时间是 30 分钟, 超过 30 分钟需要重新获取。通过 tech user 获取 token 权限比较高, 几乎可以访问 mindsphere 平台提供的一切资源, 为了您的账户安全,
tech user 信息应注意保存, 防止泄露, 如果发现 tech user 信息泄露, 为了您账号的安全, 请及时重新申请. 利用租户服务凭证信息获取 token 方法有:
1. 通过代码方式从后端程序中获取 token, 中国区获取地址格式为 https://{租户名称}.piam.cn1.mindspherein.cn/uaa/oauth/token, 代码示例如下
@RequestMapping("/getTechUser")
public String getTechUser() throws IOException, MindsphereException {
String token = "";
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Accept", "application/json");
RestTemplate restTemplate = new RestTemplate();
String url = "https://supplab.piam.cn1.mindsphere-in.cn/uaa/oauth/token";
String bodyJson = "client_id={服务凭证 id} &client_secret={服务凭证密码}
&grant_type=client_credentials";
HttpEntity<String> requestEntity = new HttpEntity<String>(bodyJson, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST,
requestEntity, String.class);
JSONObject jsonObject = new JSONObject(responseEntity.getBody());
if (!jsonObject.isNull("access_token")) {
token = jsonObject.getString("access_token");
} else {
System.out.println("ge response body access_token is null");
return null;
}
return token; }
在上述代码需要将 bodyJson="client_id={服务凭证 id} &client_secret={服务凭证密码}&grant_type=client_credentials"中的服务凭证 id 和服务凭证密码替换为您自己的服务凭证信息, 其次代码返回是一个 json 格式的字符串, 需要将字符串中 access_token 作为 token 值.
2. 利用凭证信息通过 postman 获取 token, 在 postman 中 Params 中设置为 grant_type, VAULE 为 client_credentials 或者直接在地址栏输入 https://supplab1.piam.cn1.mindsphere-in.cn/uaa/oauth/token?grant_type=client_credentials 地址;Auth 中 type 选择 Basic Auth, 然后 Username 填入服务凭证 id(client_id), Password 填入服务凭证密码(client_secret)如图所示:
3。 通过代码方式利用 access_token 直接调用 MindSphere api 或已注册的 app 的 api;调用方式基本相同只需要将调用接口进行替换即可:
- 调用 MindSphere api 地址格式为:https://gateway.cn1.mindsphere-in.cn/{MindSphere api};如: https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_model
- 调用已注册 APP API 地址格式为:https://gateway.cn1.mindsphere-in.cn /api/{app 名称}-{租户名称}/{版本信息}/{app 接口地址}, 如 https://gateway.cn1.mindsphere-in.cn/api/datasource-supplab/v1/getValue
- 代码示例:
@RequestMapping("/getTechTokenValue")
public String getTechTokenValue() throws IOException, MindsphereException {
HttpHeaders headers = new HttpHeaders();
headers.set("cache-control", "no-cache");
headers.set("Content-Type", "application/json");
String token = getTechUser();
headers.add("Authorization", token);
RestTemplate restTemplate = new RestTemplate();
String url = "https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_model";
String bodyJson = "";
HttpEntity<String> requestEntity = new HttpEntity<String>(bodyJson, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
String.class);
String responseBody = responseEntity.getBody().toString();
System.out.println("responser body:" + responseBody);
return responseBody; }
上述代码中将 url 地址替换为访问 app 地址(https://gateway.cn1.mindsphere-in.cn/api/datasourcesupplab/v1/getValue)同样有效
4. 利用 https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_model 通过 postman 工具调用 MindSphere api 或已注册 app api;调用方式基本相同只需要将调用接口进行替换即可:
- 通过 postman 调用 MindSphere api, 在 postman 中地址栏中输入 https://gateway.cn1.mindspherein.cn/api/iottimeseries/v3/timeseries/9ab3f21ff8ad43638ed74ea6e413bb72/modbus_model, 送然后选择 Auth->type->bearer Token, headers 中设置{key:Content-Type;Value:application/json} 然后在 Token 中输入 uesrtoken, 点击发送
- 通过 postman 调用 app api, 调用方式和调用 MindSphere api 一直, 只需要将 postman 中的 MindSphere api 地址替换为 https://gateway.cn1.mindsphere-in.cn/api/datasource-supplab/v1/getValue 即可
1.4. App Credential
1.4.1. 应用凭证介绍
在 app 开发过程中, app 与 MindSphere 平台或是自己后端 app 进行资源交互时, 我们推荐是应用凭证方式进行;App
Credentials( 应用凭证)是 MindSphere 平台的 token management service 管理应用凭证的一项功能, app 在开发过程中, 如果在 Developer Cockpit 中创建应用凭证, 通过应用凭证信息与 MindSphere 平台 token management service 交互获取 token, 这个 token 有效期也是 30 分钟, 但是 token 在快过期的时 token management service 会提前 5 分钟 token 置换, 用户可以不用关心有效期的问题。
通过应用凭证信息获取的 token 具备跨租户访问数据的能力, 这个功能只有在具有应用凭证的 APP 在分配到 operator 环境, 在从 operator 环境分配用户环境(IoT 用户)时, 只有 IOT 用户授予同意时, 在 operator 部署的环境中 APP 使用此 token 可以获取 IOT 用户中资源。
应用凭证支持自托管程序和 MindSphere Cloud Foundry APP, 它们之间的区别是 MindSphere Cloud Foundry APP 在 operator 对应 Cloud Foundry 中是自动将应用凭证信息设置为环境变量中, 而自托管程序应用则是保存在文件中, 需要用户自行下载。
需要注意的是 developer 环境和 operator 环境中产生的应用凭证是不一样的, 主要区别如下:
- 在 Developer 环境中的应用凭证只能在 developer 环境中有效, 不具备跨租户访问能力, 手动产生, 需要手动记录便于开发测试, 不能将将 developer 环境的应用凭证设置到 operator 环境
- 在 Operator 环境中的应用凭证也只能在 operator 环境中有效, 通过 IoT 用户授权之后具备跨租户访问能力, 自动生成应用凭证, 在 cloudfoundry 中自动设置为环境变量, selfhost 自动生成保存在 execel 文件中, 需要手动下载。
在开发过程中每个 app 的应用凭证具有唯一性且有有效期, 所以每个 app 只用使用自己的应用凭证, 不要将应用凭信息证嵌入到代码中, 尽量使用官网提供 sdk, 有的 sdk 已经封装了此类接口如(JavaSDK)或者开发语言具有获取自动获取环境变量接口, 便于应用凭证到期的时候能够自动获取延期的变量值, 也便于维护。
关于 token management service 介绍可以参考 https://developer.mindsphere.io/zh/apis/exchangetokenmanager/api-tokenmanager-overview.html 链接中的内容。
1.4.2. APP 与 Token Management Service 置换 token
在 app 应用凭证创建时会提供两个相信 client_id 和 client_secret 两个信息, 此信息只生成一次, 有效期为 365 天。App 必须提供应用凭证信息 client_id, client_secret 及注册应用 appname、appversion 和 hosttenant 名称、usertenant 名称与 token management service 置换 token, 在这个过程需要特别注意一点是 app 从 Developer Cockpit 上传时所选择 read
(受限的)和 readwrite(读和写)在生成 token 分别对应权限为 mdsp:core:Default3rdPartyTechUser 与 mdsp:core:Admin3rdPartyTechUser.
➢ 在 developer 账号中创建的应用凭证需要手动保存文件, 手动设置在环境变量中或者报错 manifest 文件中。
- 在 Cloud Foundry 中通过 cf set-env APP_NAME ENV_VAR_NAME ENV_VAR_VALUE 手动设置环境变量, 如:
cf set-env appname MDSP_KEY_STORE_CLIENT_ID client_id
cf set-env appname MDSP_KEY_STORE_CLIENT_ID client_secret
- Manifest 文件保存, 重现 push APP 设置环境变量如下
---
applications:
- name:dataSource
instances:1
path:dataSource-0.0.1-SNAPSHOT.jar
memory:1G
random-route:true
env:
HOST_ENVIRONMENT:cn1
MDSP_OS_VM_APP_NAME:app name
MDSP_OS_VM_APP_VERSION:app version
MDSP_KEY_STORE_CLIENT_ID:client_id
MDSP_KEY_STORE_CLIENT_SECRET:client_sercret
MDSP_HOST_TENANT:tenant name
MDSP_USER_TENANT:tenant name
JAVA_OPTS:'-XX:ReservedCodeCacheSize=512M
- 在 Operator Cockpit 环境中 MindSphere Cloud Foundry APP 创建应用凭证, 注册成功会自动保存在环境变量值 MDSP_KEY_STORE_CLIENT_ID, MDSP_KEY_STORE_CLIENT_SECRET 中;Self Hosted app 创建应用凭证注册成 功时会自动保存在文件中, 用户在应用注册项自行下载保存。
public String getInterfaceToken(String appName, String appVersion, String hostTenant, String
userTenant) {
String responseBody = "";
String token = "";
String bodyJson =
"{\n" + " \"appName\":\"" + appName + "\",\n" + " \"appVersion\":\"" + appVersion
+ "\",\n" + " \"hostTenant\":\"" + hostTenant
+ "\",\n" + " \"userTenant\":\"" + userTenant + "\",\n" + "
\"grant_type\":\"client_credentials\"\n" + "}";
String strClientID = "{应用凭证 Id/client_id} ";
String strClientSceret = "{应用凭证密钥/client_secret}";
String strBase64 = getBase64(strClientID, strClientSceret);
HttpHeaders headers = new HttpHeaders();
headers.set("cache-control", "no-cache");
headers.set("Content-Type", "application/json;charset=UTF-8");
headers.add("x-space-auth-key", "Bearer " + strBase64);
RestTemplate restTemplate = new RestTemplate();
String url = "https://gateway.cn1.mindsphere-in.cn/api/technicaltokenmanager/v3/oauth/token";
HttpEntity<String> requestEntity = new HttpEntity<String>(bodyJson, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST,
requestEntity, String.class);
responseBody = responseEntity.getBody();
JSONObject jsonObject = new JSONObject(responseBody);
if (!jsonObject.isNull("access_token")) {
token = jsonObject.getString("access_token");
} else {
System.out.println("ge response body access_token is null");
return;
}
System.out.println("responser body:" + token);
return token; }
// 应用凭证信息转化为 base64
public String getBase64(String clientID, String clientSceret) {
String strGorp = clientID + ":" + clientSceret;
String base64Creds = "";
try {
byte[] base64CredsBytes = Base64.encodeBase64(strGorp.getBytes("UTF-8"));
base64Creds = new String(base64CredsBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
System.out.println(e.getMessage());
}
return base64Creds; }
- 首先在 postman 地址栏中输入 https://gateway.cn1.mindsphere-in.cn/api/technicaltokenmanager/v3/oauth/token 地址
- 首先使用 https://www.base64encode.org 网址中工具 APP 应用凭证 client_id 和 client_secret 转化为 Base64, 转化格式为”client_id:client_secret”;点击 ENCODE 将转化 base64 保存。
- 在 postman 中设置 headers, 添加
Key:value 为 cache-control:no-cache
Key:value 为 Content-Type:application/json
- 添加 body, body 设置为 json 格式
{
"appName":"app name",
"appVersion":"app version",
"hostTenant":"operator 租户名称",
"userTenant":"iot 用户名称",
"grant_type":"client_credentials"
}
对于未发布的 app 在 Developer 环境中 hostTenant 和 userTenant 设置为 developer 租户名称, 已经发布的 app
hostTenant 和 userTenant 根据 app 分配情况, 从而来设置 operator 租户名称和 iot 用户名称, 有时候为测试同时设置
为 operator 租户名称, 但是不能同时设置为 iot 租户名称。
如:
{
"appName":"datasource",
"appVersion":"v1", //
"hostTenant":"supplab", //必须填 operator tenant 名称如果传参数的时候{{ hostTenant name}}
"userTenant":"supplab" // lot 用户的 tetant 名称如果传参数的时候{{ userTenant name}},
"grant_type":"client_credentials"
}
- 点击发送获取 access_token通过上述获取的 access_token 访问 MindSphere api 或 app api 方法与 Tenant Credentials 中 access_token 访问MindSphere api 或 app api 方法一致, 请参考前面的内容.
1.5. WebScoket
var Stomp = require('stompjs');
var WebSocket = require('ws');
var SockJS = require("sockjs-client");
// ajax post 请求默认添加请求头
var cookie = "SESSION=NmVkYzZjOWYtYzdhNy00NzZkLTgxYzUtZDZkMGIyOTYyMGQy";
var stompClient = null;
function connect() {
var url = "https://supplab1-websocket-supplab1.cn1.mindsphere-in.cn/websocket/stomp";
var socket = new WebSocket(
url, {
headers: {
"Cookie": cookie
} }
);
stompClient = Stomp.over(socket);
stompClient.connect(
{},
function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
sendName();
},
function (error) {
console.log('Failed to connect, unsuccessfully: [' + error + ']');
}
);
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': "Hello world is my name" }));
}
function showGreeting(message) {
console.log("Received message: " + message);
}
connect();
@Configuration
@EnableWebSocketMessageBroker
@EnableScheduling
public class MessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {
public static final String STOMP_ENDPOINT = "/websocket/stomp";
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint(STOMP_ENDPOINT).setAllowedOrigins("*");
registry.addEndpoint(STOMP_ENDPOINT).setAllowedOrigins("*").withSockJS();
} }
更多推荐
所有评论(0)