中文简体 English
IVY单点登录(SSO)API
版本记录:
修订日期 | 版本号 | 修改人 | 描述 |
---|---|---|---|
2019-12-14 | V1.0 | 杨昭炎 | 文档在线发布 |
版权声明:
©2019爱为物联保留所有权利。未经爱为物联书面授权,严禁将本文档的全部或部分内容用于印刷或制作电子文档。
本文档中包含的信息仅供爱为物联人员、设备的授权用户以及获得爱为物联授权的人员使用,严禁用于其他用途。本文档信息如有更改,恕不另行通知。
商标声明:
Ivyiot™和爱为物联标志是爱为物联的注册商标和服务标志。其他产品、品牌或服务名称是其各自所有者的商标或服务标志。未经爱为物联书面许可,严禁复制、展示或使用其商标或服务标志。
参考文件:
爱为物联不负责提供本文档中随设备引用的所有文档。爱为物联保留决定随产品和服务提供哪些文档的权利。
1. 简介
1.1 文档介绍
本文档介绍了Ivy SSO认证平台对接流程及详细接口对接明细,以便商户集成对接,从而实现登陆Ivy平台。
1.2 适用人群
本文档专为需要接入IVY平台的产品、开发、测试等相关人员编写。
2. 接入说明
2.1 认证要求
2.1.1 服务器要求
- 服务器必须可以外网访问。
- 对接我司国外业务,则需要有国际网络或位于国外的服务器。
- 安全原因服务器需要实现https协议,并配置对应的域名。
- 服务器时间需要能保证实时同步为准确时间。
2.1.2 对接必要配置
A. 客户端id及secret
clientId和clientSecret是在SSO登陆过程中IVY平台用于服务器鉴权所需必要选项,需要商务生成并提供。B. 实现token校验及获取用户信息接口
在对接过程中,IVY平台需要对商户提供的token进行校验,故需要商户实现token校验接口并返回用户信息。在处理更新和删除用户信息的回调中,需要对商户用户信息进行确认,故需要商户实现通过uuid获取用户信息接口(具体接口明细详见鉴权认证部分)。
2.2 交互流程
2.2.1 基本说明
- A. 商户通过App使用token登陆我司,获取到refreshToken和accessToken。
- B. accessToken过期,则可以使用refreshToken刷新获取到新的accessToken。
- C. 如果B中的 refreshToken过期,则需要重新发起A的登陆流程。
- D. 商户通过回调方法,更新或者删除在我司系统中的用户数据信息。
2.2.2 时序图
3. 对接明细
3.1 API规范
- 现在以GET方式调用如下示例接口来说明对接IVY API的流程:
https://api.ivyiot.com/sso/user_callback?operation=UPDATE&uuid=204242f98b4247998a1e52496331e6a
3.1.1 确定参数
S1. 确定基本参数
- A. 确定请求方式
示例:GET - B. 获取当前系统的unix时间戳
示例:1559531103 - C. 确定当前使用的API对接版本
示例:1.0,当前API版本为1.0 - D. 确定url
示例:/sso/user_callback - E. 参数排序:需要先对所有参数按照参数名称进行排序,然后使用”参数名=参数值”方式将所有参数用”&”连接
示例:operation=UPDATE&uuid=204242f98b4247998a1e52496331e6a0 - F. 客户端clientId和clientSecret
S2. 创建签名的字符串
- 获取需要加密的字符串,使用请求方式+”\n”+Url+”\n”+排序后的参数+”\n”+unix时间戳
示例: GET\n/sso/user_callback\noperation=UPDATE&uuid=204242f98b4247998a1e52496331e6a0\n1549266882
S3. 创建签名
- 加密key:clientSecret + unixtimestamp
- 加密方式:使用key对2中生成的字符串进行HMAC-SHA256加密获取到
sign= 92e508b14cf405d6508930bdf38ad2f439054c3a43281860287d3c3ad8b7eee9
3.1.2 创建请求
- A. 确定请求方式,url及参数如上
- B. 生成http请求头
x-client-time 客户端请求创建的linux时间戳
x-version 请求版本号
x-client-Id 客户端id
sign 3.1.1中创建的签名
3.1.3 响应状态码
- 网络状态码
200 正常返回
401 错误返回,如没有响应内容则为鉴权失败,如存在响应内容,请针对错误码进行处理。
【具体错误码处理参照接口明细中的说明】
3.2 商户客户端处理流程
S1. 获取请求信息
- A. 获取到请求方式
示例:GET/POST
- A. 获取到请求方式
- B. 获取到url
示例:/sso/user_callback
- B. 获取到url
- C. 获取请求参数,并按照参数名进行排序并拼接为字符串
示例:operation=UPDATE&uuid=204242f98b4247998a1e52496331e6a0
- C. 获取请求参数,并按照参数名进行排序并拼接为字符串
- D. 获取到请求的unix时间
示例:1559531103
- D. 获取到请求的unix时间
S2. 请求验证
- A. 判断请求是否超时,最大超时时长为15秒
- B. 参照3.3.1中的第3步计算签名sign并与请求头中的签名进行比较
S3. 处理业务并按照指定结果返回(具体到每个接口的返回参照接口明细)。
3.3 IVY接口实现
3.3.1 使用token登录
接口描述:
- 该 API 由应用调用,通过token登录到IVY服务。
- 发起者: 移动应用/其他终端用户应用
- 接受者: IVY服务
请求URL:
- https://{HOST}/sso/authorize_by_token
请求方式:
- POST
请求头:
- 参考3.1.2“生成http请求头”。
请求参数:
参数名 | 数据类型 | 是否必须 | 说明 |
---|---|---|---|
token | String | 必选 | 授权Token |
响应状态码:
- 200 请求成功
- 401 请求失败
返回示例:
正确时返回:
Response Code: 200
Response Body:
{
"accessToken":"8e34108f0dfe4efeac29701a1ae16fe5",
"refreshToken":"67fd1a923d104ac792c1bf69532a1e70",
"expiresIn":86400
}
失败时返回:
Response Code: 401
Response Body:
{
"failureDetails":"partner authorization denied",
"errorCode":"OP0051",
"expiresIn":0
}
返回参数说明:
参数名 | 说明 |
---|---|
errorCode | 错误类型,见返回码 |
failureDetails | 错误描述 |
accessToken | 访问令牌 |
refreshToken | 刷新令牌 |
expiresIn | 访问令牌过期存活时间【秒】 |
错误码说明:
- 无
3.3.2 刷新accessToken接口
接口描述:
- 该 API 由应用调用,通过refreshToken刷新accessToken接口。
- 发起者: 移动应用/其他终端用户应用
- 接受者: IVY服务
请求URL:
- https://{HOST}/sso/refresh_token
请求方式:
- POST
请求头:
- 参考3.1.2“生成http请求头”。
请求参数:
参数名 | 数据类型 | 是否必须 | 说明 |
---|---|---|---|
refreshToken | String | 必选 | 刷新令牌 |
响应状态码:
- 200 请求成功
- 401 请求失败
返回示例:
正确时返回:
Response Code: 200
Response Body:
{
"accessToken":"8e34108f0dfe4efeac29701a1ae16fe5",
"refreshToken":"67fd1a923d104ac792c1bf69532a1e70",
"expiresIn":86400
}
失败时返回:
Response Code: 401
Response Body:
{
"failureDetails":"refreshtoken expired",
"errorCode":"030051",
"expiresIn":0
}
返回参数说明:
参数名 | 说明 |
---|---|
errorCode | 错误类型,见返回码 |
failureDetails | 错误描述 |
accessToken | 访问令牌 |
refreshToken | 刷新令牌 |
expiresIn | 访问令牌过期存活时间【秒】 |
错误码说明:
返回码 | 提示 | 说明 |
---|---|---|
030091 | tokenInfo not exists | token不存在 |
030051 | refreshtoken expired | refreshtoken过期 |
3.3.3 用户信息回调接口
接口描述:
- 该 API 由应用调用,回调通知IVY平台更新或删除影子账户信息。
- 发起者: 移动应用/其他终端用户应用
- 接受者: IVY服务
请求URL:
- https://{HOST}/sso/user_callback
请求方式:
- POST
请求头:
- 参考3.1.2“生成http请求头”。
请求参数:
参数名 | 数据类型 | 是否必须 | 说明 |
---|---|---|---|
operation | String | 必选 | UPDATE或DELETE |
uuid | String | 必选 | 用户的不可变唯一标识符 |
响应状态码:
- 200 请求成功
- 401 请求失败
返回示例:
正确时返回:
Response Code: 200
Response Body:
{
"errorCode":"",
"failureDetails":""
}
失败时返回:
Response Code: 401
Response Body:
{
"failureDetails":"refreshtoken expired",
"errorCode":"030051"
}
返回参数说明:
参数名 | 说明 |
---|---|
errorCode | 错误类型,见返回码 |
failureDetails | 错误描述 |
错误码说明:
- 无
3.4 商户实现接口
3.4.1 校验token有效性
接口描述:
- IVY服务使用此 API 来校验token是否有效,并获取用户信息。
- 发起者: IVY服务
- 接受者: 商户服务端
请求URL:
- 自定义(但需要给到我司,参考:/idp/is_valid_token)
请求方式:
- GET
请求头:
- 无
请求参数:
参数名 | 数据类型 | 是否必须 | 说明 |
---|---|---|---|
token | String | 必选 | 授权Token |
响应状态码:
- 200 请求成功
- 401 请求失败
返回示例:
正确时返回:
Response Code: 200
Response Body:
{
"errorCode":"",
"failureDetails":"",
"user":{
"uuid":"9314839c623048e88afdcd0e9802e2aa",
"username":"9314839c623048e88afdcd0e9802e2aa@ivyiot.io",
"name":"233671",
"nickname":"",
"phone":"",
"country":""
}
}
失败时返回:
Response Code: 401
Response Body:
{
"failureDetails":"token is invalid",
"errorCode":"xxxxxx"
}
返回参数说明:
参数名 | 说明 |
---|---|
errorCode | 错误类型,见返回码 |
failureDetails | 错误描述 |
user | 用户对象 |
user.uuid | 用户的不可变唯一标识符 |
user.username | 用户邮箱 |
user.name | 用户全名 |
user.nickname | 昵称 |
user.phone | 电话 |
user.country | 国家 |
错误码说明:
- 无
3.4.2 查询用户信息
接口描述:
- IVY服务使用此 API 来使用uuid查询用户信息。
- 发起者: IVY服务
- 接受者: 商户服务端
请求URL:
- 自定义(但需要给到我司,参考:/idp/get_user_profile)
请求方式:
- GET
请求头:
- 无
请求参数:
参数名 | 数据类型 | 是否必须 | 说明 |
---|---|---|---|
uuid | String | 必选 | 用户的不可变唯一标识符 |
响应状态码:
- 200 请求成功
- 401 请求失败
返回示例:
正确时返回:
Response Code: 200
Response Body:
{
"errorCode":"",
"failureDetails":"",
"user":{
"uuid":"9314839c623048e88afdcd0e9802e2aa",
"username":"9314839c623048e88afdcd0e9802e2aa@ivyiot.io",
"name":"233671",
"nickname":"",
"phone":"",
"country":""
}
}
失败时返回:
Response Code: 401
Response Body:
{
"failureDetails":"user profile not exists",
"errorCode":"xxxxxx"
}
返回参数说明:
参数名 | 说明 |
---|---|
errorCode | 错误类型,见返回码 |
failureDetails | 错误描述 |
user | 用户对象 |
user.uuid | 用户的不可变唯一标识符 |
user.username | 用户邮箱 |
user.name | 用户全名 |
user.nickname | 昵称 |
user.phone | 电话 |
user.country | 国家 |
错误码说明:
- 无
4 代码示例
4.1 Java代码示例
- A. 请求校验
// 校验时间x-client-time与服务器时间间隔不能超过15秒
String clientTime = headers.get(IvyConstant.KEY_HEADER_CLIENT_TIME);
if (!isClientTimeValid(clientTime)) {
return false;
}
// 校验sign是否匹配
String partnerSign = headers.get(IvyConstant.KEY_HEADER_SIGN);
String sign = IvyAuthUtil.getPartnerSign(uri, httpMethod, clientTime, params);
if (StringUtils.isEmpty(partnerSign) || !partnerSign.equals(sign)) {
log.warn("IvyHttpInterceptor.handler not passed. sign is invalid. partnerSign={}, sign={}", partnerSign, sign);
return false;
}
- B. 计算sign
String canonicalUri = getCanonicalUri(uri);
String canonicalQueryString = getCanonicalQueryString(params);
// 计算toSign
String toSign = httpVerb + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + time;
// 计算signature
String signature = OpenEncrypt.ivySha256HMAC(secret + time, toSign, AylaHttpClient.CHARSET_UTF8);
return signature;