应用快速接入与单点登录指南
WorkPlus是企业移动通信平台和企业移动应用平台的统一,它作为企业移动应用的统一入口,支持各种轻应用和原生应用的接入。各种应用在WorkPlus平台注册之后会出现在WorkPlus移动端的应用中心,供用户安装和访问。应用可以以当前登录用户的身份访问WorkPlus平台以RESTful Web Service的形式发布出来的功能API,获得消息收发、企业通信录访问等能力。
WorkPlus平台API受OAuth 2.0协议保护。要能够通过REST访问WorkPlus平台,需要经过下面的步骤:
- 由WorkPlus系统管理员登录到WorkPlus管理平台注册应用,生成AppKey和AppSecret;
- 从WorkPlus移动端获取tenant_id;
- 使用AppKey、AppSecret和tenant_id从WorkPlus平台获取access_token,作为应用的身份凭证;
- 获取WorkPlus移动端当前登录用户的标识,实现单点登录(可选)
- 以access_token为查询参数,访问平台API。
其中第1步是一次性的,仅在应用注册到平台时一次性生成AppKey和AppSecret(per app);第2、3、4步频率高一些,每次应用登录到WorkPlus平台时均需申请一个新的access_token(per session);第5步频率最高,应用对WorkPlus的每次REST访问都需要传入access_token(per request)。
下面详细论述各个步骤。
第一步:到WorkPlus管理平台注册应用,生成AppKey和AppSecret
如果你的应用要能够接入WorkPlus,出现在WorkPlus应用中心,必须首先由WorkPlus系统管理员在WorkPlus管理平台注册你的应用,生成AppKey和AppSecret。AppKey代表应用的标识,AppSecret代表应用的凭证,这两者可以分别类比个人用户的username和password。
应用开发者从WorkPlus系统管理员那里获取AppKey和AppSecret之后,应保存起来,使得应用代码可以使用它们登录到WorkPlus。
第二步:从WorkPlus移动端获取tenant_id
WorkPlus是个支持多租户的云平台,每个租户(对应于WorkPlus云平台的一个客户,通常是一个公司或其他组织)通过唯一的tenant_id标识,在WorkPlus上拥有和管理它自己的组织机构、人员和应用。移动应用登录到WorkPlus平台以访问平台API时,必须提供tenant_id给平台进行验证和关联。
在为每个租户生成WorkPlus移动端App时会将该租户的tenant_id一并打包,因此,部署在应用中心中的轻应用和原生应用就可以通过与WorkPlus移动端的交互获取该tenant_id。
Android原生应用
在Launcher Activity的onCreate()方法中,通过
String tenantId = getIntent().getStringExtra("KEY_TENANT_ID");
获取tenant_id。
iOS原生应用
在AppDelegate类的
(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
方法中这样提取tenant_id:
//url结构
//[Scheme]&ticket=[ticket]&tenantId=[tenantId]
//[Scheme]:后台添加版本时输入的跳转协议
//[ticket]: ticket的值
//[tenantId]: tenant_id
//获取url里面的参数部分
NSString *text = [[url query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//然后按url参数的方式去解析,先找“&”
NSArray *arr = [text componentsSeparatedByString:@"&"];
//然后查找以ticket开头的字段
for (int i = 0; i < arr.count; i ++) {
NSString* str = [arr objectAtIndex:i];
if ([str hasPrefix:@"tenantId"]) {
//然后再按“=”拆分
NSArray *array = [str componentsSeparatedByString:@"="];
NSString *tenantId = [array objectAtIndex:1];
NSLog(@"%@", tenantId);
}
}
tenantId变量的值就是要提取的tenant_id
轻应用
轻应用可以直接访问WorkPlus的Cordova接口获取tenant_id。
(1)在页面中引用Cordova.js:
<script src="applocal://www/cordova.js"></script>
(2)代码这样调用:
cordova.exec(
function(result) {
console.log("获取tenant_id成功");
},
function(error) {
console.log("获取tenant_id失败");
},
"WorkPlus_Auth",
"getTenantId",
[]
);
(3) 如果没有异常,result就是调用getTenantId()接口的结果:
{"tenant_id": "1434132518343254"}
tenant_id就是“1434132518343254”。
第三步:使用AppKey、AppSecret和tenant_id获取access_token
应用启动时,使用AppKey、AppSecret和tenant_id通过REST方式登录到API服务器,换取access_token.
POST https://api.workplus.io/token
(如果您的WorkPlus是私有化部署,请根据实际情况修改API服务器的域名/IP和端口)
参数是个JSON对象:
{
"grant_type": "client_credentials",
"scope" : "app",
"tenant_id" : "租户ID",
"client_id" : "appKey",
"client_secret" : "appSecret"
}
其中:
- grant_type属性:必须是"client_credentials"。
- scope属性:必须是"app"。
- tenant_id属性:填写你的租户标识(上文第二步中获得的)。
- client_id属性:填写应用的AppKey。
- client_secret属性:填写应用的AppSecret.
另外,需要设置HTTP Header:
Content-Type="application/json"
如果AppKey和AppSecret是正确的,系统会返回一个JSON对象:
{
"status": 0,
"message": "Everything is ok.",
"result": {
"access_token": "token",
"issued_time": "token创建时间",
"expire_time": "token过期时间"
}
}
从结果JSON对象的"result"属性(代表另一个JSON对象)中提取“access_token”属性,保存起来备用,这就是你本次会话的access_token。
说明:
“expire_time”是这个access_token的过期时间。这个时间之后,access_token就会失效。应用必须重新登录到WorkPlus API服务器,获取新的access_token。
第四步:获取WorkPlus移动端当前登录用户的标识,实现单点登录(可选)
WorkPlus移动端的应用中心中的大部分应用,往往需要和WorkPlus用户系统集成。当用户登录WorkPlus移动端之后,访问应用中心中的移动应用时,后者可以自动识别当前用户,而不需要在应用中重新登录一次。应用此后的操作都以当前用户的身份进行。
WorkPlus实现单点登录的机制是:当用户在WorkPlus应用中心中点击打开原生应用时,WorkPlus会自动为当前登录用户生成一个ticket,移动应用可以将这个ticket和传递到后台验证其合法性,如果ticket是合法的,系统将返回当前登录用户的身份标识。
在应用代码中,实现单点登录获取当前用户标识的具体步骤是:
- 获取ticket;
- 向后台验证ticket有效性,获取当前用户标识。
具体描述如下:
1. 获取ticket
iOS、Android和轻应用获取ticket的方式各不相同。
Android原生应用
在Launcher Activity的onCreate()方法中,通过
String ticket = getIntent().getStringExtra("KEY_USER_TICKET")
获取ticket。
iOS原生应用
在AppDelegate类的
(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
方法中这样提取ticket:
//url结构:
//[Scheme]&ticket=[ticket]&tenantId=[tenantId]
//[Scheme]:后台添加版本时输入的跳转协议
//[ticket]: ticket的值
//[tenantId]: tenant_id
//获取url里面的参数部分
NSString *text = [[url query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//然后按url参数的方式去解析,先找“&”
NSArray *arr = [text componentsSeparatedByString:@"&"];
//然后查找以ticket开头的字段
for (int i = 0; i < arr.count; i ++) {
NSString* str = [arr objectAtIndex:i];
if ([str hasPrefix:@"ticket"]) {
//然后再按“=”拆分
NSArray *array = [str componentsSeparatedByString:@"="];
NSString *ticket = [array objectAtIndex:1];
NSLog(@"%@", ticket);
}
}
ticket变量的值就是要提取的用户ticket。
轻应用
轻应用可以直接访问WorkPlus的Cordova接口获取ticket。
(1)在页面中引用Cordova.js:
<script src="applocal://www/cordova.js"></script>
(2)代码这样调用:
cordova.exec(
function(result) {
console.log("获取ticket成功");
},
function(error) {
console.log("获取ticket失败");
},
"WorkPlus_Auth",
"getUserTicket",
[]
);
(3) 如果没有异常,result就是调用getUserTicket()接口的结果:
{"user_ticket": "1434132514343214"}
ticket内容就是“1434132514343214”。
2. 验证ticket有效性,获取当前用户标识
iOS、Android原生应用和轻应用验证ticket并获取当前用户标识的方式基本相同,都是将ticket传送到后台,验证其合法性。如果该ticket确实存在,后台将返回当前用户身份标识和其他相关信息。
URL:
GET https://api.workplus.io/ticket/[ticket]?access_token=[access_token]
用你的ticket和access_token(从上面第三步获取)分别替换上面url的[ticket]和[access_token]占位符。如果您的WorkPlus是私有化部署,请根据实际情况修改API服务器的域名/IP和端口。
返回结果是一个JSON对象:
{
"status": 0,
"message": "Everything is ok.",
"result": {
"tenant_id": 租户ID,
"client_id": 当前登录用户名,
"device_id": 设备ID
}
}
result中的client_id就是当前登录用户的用户名。
最后一步:使用access_token访问平台API
获得access_token之后,应用就可以使用它作为查询参数,以REST的方式访问WorkPlus的平台API。
WorkPlus RESTful API统一以JSON对象作为参数对象和返回值。在下面的例子中,当需要POST或PUT一个REST资源时,都需要设置HTTP Header参数:
Content-Type="application/json"
基本上,对每个WorkPlus API访问的返回值都是一个JSON对象。该对象拥有下述属性:
- status属性:用正整数代表的调用结果状态。0代表一切正常,不同的非0值代表发生了不同的异常情况。
- message属性:对调用结果的文字性描述,如果调用正常,则内容是“Everything is ok.”;如果调用异常,则描述具体的异常消息。
- result属性:通常是一个JSON对象,代表调用正常的情况下返回的真实结果。
下面是一些例子(记得将“:access_token”替换为第二步获得的access_token,如果您的WorkPlus是私有化部署,请根据实际情况修改API服务器的域名/IP和端口):
例子1:发送文本消息
如果要向用户zhangsan和lisi发送文本消息,POST到/app/mbox资源:
POST https://api.workplus.io/app/mbox?access_token=:access_token
(如果您的WorkPlus是私有化部署,请根据实际情况修改API服务器的域名/IP和端口)
参数JSON对象:
{
"type": "TEXT",
"body": {
"content": "你好!"
},
"client_ids": ["zhangsan", "lisi"]
}
如果一切正常,服务器将返回下述JSON对象:
{
"status": 0,
"message": "Everything is ok.",
"result": {
"id": "推送计划ID",
"app_id": "应用id",
"tenant_id": "租户id",
"material_id": "",
"expects": "",
"fails": "",
"oks": "",
"create_time": "创建时间",
"refresh_time": "刷新时间",
"expect_time": ""
}
}
例子2:发送图文消息
如果要向用户zhangsan和lisi发送图文消息,POST到/app/mbox资源:
POST https://api.workplus.io/app/mbox?access_token=:access_token
参数JSON对象:
{
"type": "ARTICLE",
"body": {
"articles":
[
{
"url" : "文章打开地址",
"show_cover" : true,
"cover_url" : "图文封面图片url",
"summary" : "文章摘要",
"create_time" : 1433314282603,
"content_source" : "文章原文链接",
"author" : "文章作者",
"sort" : 0,
"title" : "文章标题",
"content" : "<p>文章内容</p>"
}
]
},
"client_ids": ["zhangsan", "lisi"]
}
如果一切正常,服务器将返回下述JSON对象:
{
"status": 0,
"message": "Everything is ok.",
"result": {
"id": "推送计划ID",
"app_id": "应用id",
"tenant_id": "租户id",
"material_id": "",
"expects": "",
"fails": "",
"oks": "",
"create_time": "创建时间",
"refresh_time": "刷新时间",
"expect_time": ""
}
}
例子3:获取机构信息
GET https://api.workplus.io/organization/:org_id?access_token=:access_token
如果一切正常,服务器将返回下述JSON对象:
{
"status": 0,
"message": "Everything is ok.",
"result": {
"tenant_id" : "租户标识",
"id" : "机构标识",
"name" : "名字",
"sn" : "机构编号",
"tel" : "电话号码",
"serial_no" : "机构唯一序列号(比如第三方的系统标识)",
"path" : "路径",
"type" : "类型[公司(CORP), 部门(DEPT)]",
"root" : "是否是根公司",
"created" : "创建时间",
"last_modified" : "最后修改时间",
"expired" : "过期时间",
"disabled" : "是否有效",
"parent_org_id" : "父机构标识",
"parent_org_name" : "父机构名称",
"root_comId" : "根机构标识",
"root_comName" : "根机构名称",
"sort_order" : "排序号"
}