快速参考

所有的 API 访问都是通过 HTTPS 进行的.API 访问需要在 https://www.scanify.com 域名下。

注册

URL HTTP 功能
/api/user POST 用户注册
/api/user/sendSmsCode POST 请求重新发送手机号码注册OTP验证短信
/api/user/verifySmsCode/<code> POST 请求验证注册手机OTP短信验证码。
/api/<code> POST 请求使用 "验证码"
/api/user/<id> GET 获取用户信息
/api/user/<id>/updatePassword PUT 更新密码,要求输入旧密码。

登陆

URL HTTP 功能
/api/login GET 用户登录
/api/login/sendSmsCode POST 请求发送手机号码登录OTP短信。
/api/login/verifySmsCode/<code> POST 请求验证登陆手机OTP短信验证码。

用户操作

URL HTTP 功能
/api/user/<id> GET 获取用户信息
/api/user/<id>/updatePassword PUT 更新密码,要求输入旧密码。

app保护

URL HTTP 功能
/api/user/protect/ PUT app请求保护完成。
/api/user/protect/<code> POST app请求保护验证。

客户端保护

URL HTTP 功能
/api/protect/ POST 请求保护某个用户,返回二维码URL。
/api/protect/<id> GET 请求保护结果。

签名方式

暂定使用SHA1数字签名标准。

请求格式

对于 POST 和 PUT 请求, 请求的主体必须是 JSON 格式, 而且 HTTP header 的 Content-Type 需要设置为 application/json。

客户端验证是通过 HTTP header 来进行的, X-Scanify-Application-Id 头标明正在运行的是哪个客户端程序。

安全的验证方式

用户除了需要传递 X-Scanify-Application-Id 的 http 头表示 App id外,还需要传递 X-Scanify-Application-Sign 头,它的值要求是一个形如 sign,timestamp 的字符串,其中:

  • sign(必须)- 将 timestamp 加上 app key 组成的字符串做 sha1 签名。
  • timestamp(必须)- 客户端产生本次请求的 unix 时间戳,精确到毫秒。

响应格式

对于所有的请求的响应格式都是一个 JSON 对象.

一个请求是否成功是由状态码标明的. 一个 2XX 的状态码表示成功, 而一个 4XX 表示请求失败. 当一个请求失败时响应的主体仍然是一个 JSON 对象, 但是总是会包含 code 和 msg 这两个字段, 可以用它们来进行调试。具体的响应码解释待定。 举个例子, 如果尝试用不允许的 app key 来请求会得到如下信息:


{
  "code": 105,
  "msg": "未知的的客户端请求"
}

数据类型

对象格式

通过 REST API 保存数据需要将对象的数据通过 JSON 来编码. 您只需要设置 key-value 对就可以, 后端会解析它. 举个例子, 假设您注册一个用户信息. 一个简单的对象可能包含:


{
	"phone":"138xxxxxxxx",
	"password":"xxxxxx",
	"smsCode":"6位短信验证码"
}
  

Key 必须是字母和数字组成的 String,使用驼峰命名法(如手机号为phone)。Value 可以是任何可以 JSON 编码的东西.
详细请参考具体对象信息

日期

类似createdAt(创建时间)、updatedAt(更新时间)等所有日期格式 都是采用 UTC 时间戳, 以 ISO 8601 标准和毫秒级精度储存:YYYY-MM-DDTHH:MM:SS.MMMMZ, 如:


  "createdAt": "2015-08-20T02:06:57.931Z",
  "updatedAt": "2015-08-20T02:06:57.931Z"
  

数组

通用数组格式为:


  "arrayColor":["red","green"]
  

用户

不仅在移动app 上, 在所有客户端中的用户都尽量统一注册登录流程. 通过 REST API 访问用户的账户.

注册

注册第一步

注册一个新用户时 phone 和 password 字段都是必要的.Password 字段会以和其他的字段不一样的方式处理, 它在储存时会被加密而且永远不会被返回给任何来自客户端的请求.

app提交注册

为了注册一个新的用户, 需要向 user 路径发送一个 POST 请求, 例子:


POST https://www.scanify.com/api/user
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "Content-Type": "application/json;charset=utf-8"
    }
  Data
    {"phone":"138xxxxxxxx","password":"p_n7!-e8"}

Scanify服务器返回

app提交手机号和密码后,Scanify会验证手机号码唯一性,如果没有注册过,则会创建新用户并发送OTP短信到这个手机号,同时返回给app, sessionToken 可以被用来认证这名用户随后的请求


  {
  "createdAt": "2015-11-07T20:58:34.448Z",
  "id": "143214",
  "sessionToken": "pnktnjyb996sj4p156gjtp4im"
  "code": 200,
  "msg": "Created"
  }

注册第二步

app端要求验证OTP短信

app跳转到第二步要求输入收到的短信验证码,注意:注册或登录以后的操作都必须加入一个 X-Scanify-Session-Token 头部来请求其它操作

如果没有收到验证码,可重新发送(要包含sessionToken):


POST https://www.scanify.com/api/user/sendSmsCode
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "X-Scanify-Session-Token: pnktnjyb996sj4p156gjtp4im",
      "Content-Type": "application/json;charset=utf-8"
    }

服务器收到请求重新发送短信并返回:


  {
  "code": 200,
  "msg": "Created"
  }

app输入短信验证码并发送:


POST https://www.scanify.com/api/user/verifySmsCode/234fss
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "X-Scanify-Session-Token: pnktnjyb996sj4p156gjtp4im",
      "Content-Type": "application/json;charset=utf-8"
    }

Scanify服务器返回

服务器验证最新的OTP,验证成功时该用户才视为激活状态


  {
  "code": 200,
  "msg": "success"
  }

登陆

用户登陆和注册流程类似,只是调用接口不同而已。同时登陆后同样会返回sessionToken。

用户操作

获取用户信息

app发送请求(要包含sessionToken):


GET https://www.scanify.com/api/user/143214
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "X-Scanify-Session-Token: pnktnjyb996sj4p156gjtp4im",
      "Content-Type": "application/json;charset=utf-8"
    }

服务器收到请求返回JSON对象, 除了密码以外. 也包括了 createdAt,updatedAt 和 id 字段:


  {
  "phone": "138xxxxxxxx",
  "createdAt": "2014-11-07T20:58:34.448Z",
  "updatedAt": "2014-11-07T20:58:34.448Z",
  "id": "2342525",
  "code": 200,
  "msg": "sucess"
  }

更新密码

app发送请求(要包含sessionToken):


PUT https://www.scanify.com/api/user/143214/updatePassword
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "X-Scanify-Session-Token: pnktnjyb996sj4p156gjtp4im",
      "Content-Type": "application/json;charset=utf-8"
    }
  Data
    {"old_password":"the_old_pass", "new_password":"the_new_pass"}

服务器收到请求返回:


  {
  "code": 200,
  "msg": "sucess"
  }

保护

通过二维码的方式保护账户安全,以下分别为服务器与app之间和服务器与客户端直接的交互方法

app端

请求保护验证

扫描二维码后解析出保护URL并请求这个URL,URL中已包含保护随机码,除此之外还需要传递用户id,请求方法:


PUT https://www.scanify.com/api/user/protect/sfdsafsafdsaf
  Headers
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "X-Scanify-Session-Token: pnktnjyb996sj4p156gjtp4im",
      "Content-Type": "application/json;charset=utf-8"
    }
  Data
    {"id":"143214"}

服务器收到请求并验证随机码后,通过用户id创建一条保护记录,返回是否允许保护, 同时会返回一个保护id:


  {
  "protectId": "fdsajfdsjakfksdajfjkafjfsf",
  "code": 200,
  "msg": "sucess"
  }

保护确认

app收到验证成功后用手势、语音等方式确认用户,然后给服务器回复保护成功确认, 相当于请求修改保护状态state:


PUT https://www.scanify.com/api/user/protect/
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "X-Scanify-Session-Token: pnktnjyb996sj4p156gjtp4im",
      "Content-Type": "application/json;charset=utf-8"
    }
  Data
    {"protectId":"fdsajfdsjakfksdajfjkafjfsf",'state':'1'}

服务器收到请求返回成功并保护结束:


  {
  "code": 200,
  "msg": "sucess"
  }

支付客户端

请求保护某个用户

客户端和Scanify交互要保护更多用户信息在里面,包含:

  • clientUserID(必须)- 就是客户端的用户id,比如商户或个人用户的id。
  • componentId(必须)- 代表客户端的细化组件id。
  • code(必须)- 代表客户端的某个保护操作代码。
  • remarks(可选)- 保护操作说明。

钱包请求app需要的保护验证URL,用于生成二维码, 此时:


PUT https://www.scanify.com/api/protect/
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "Content-Type": "application/json;charset=utf-8"
    }
  Data
    {"clientUserID":"23432432432",'componentId':'24241441441',"code":"10","remarks":"支付保护"}

服务器收到请求后,首先通过clientUserID查询Scanify用户表中是否存在记录,包含以下几种情况:

  • 不存在clientUserID: 如果没有将创建一条用户记录(需要注册)。
  • 存在clientUserID记录但没有注册完成:(需要重新注册)。
  • 存在并已注册完成 - app扫描后可以直接验证保护。

服务器收到请求后将返回上面APP验证请求的URL(即/api/user/protect/<code>,code是服务器生成的保护随机码 - 随机码怎么存储还没有考虑好),客户端通过这个URL生成二维码:


  {
  "url": "https://www.scanify.com/api/user/protect/sfdsafsafdsaf";
  "code": 200,
  "msg": "sucess"
  }

请求保护结果

得到二维码显示到网页后需要获取用户保护结果, 在客户端有这么几种方法:

  1. Scanify服务器直接给客户端服务发验证结果, 同时通过网页轮询技术直接请求Scanify服务器,有可能遇到跨域的问题,但是这个方法最直接高效。
  2. Scanify服务器直接给客户端服务发验证结果,然后通过网页轮询技术请求客户端服务器,这种方法
  3. Scanify服务器直接给客户端服务发验证结果,然后客户端服务器通过服务器推技术给网页发结果,这种方法最安全,但是代价稍高,需要服务器支持。

综上所述,客户端必须提供验证结果的接口,类似支付验证的retrunUrl, Scanify服务器会Post验证结果信息给客户端,同时提供客户端请求Scanify的接口:


GET https://www.scanify.com/api/protect/234234234
  Headers 
    {
      "X-Scanify-Application-Id": "n35a5fdhawz56y24pjn3u9d5zp9r1nhpebrxyyu359cq0ddo",
      "X-Scanify-Application-Sign": "28ad0513f8788d58bb0f7caa0af23400,1389085779854",
      "Content-Type": "application/json;charset=utf-8"
    }

服务器收到请求返回保护详情,保护结束


  {
  "url": "https://www.scanify.com/api/user/protect/sfdsafsafdsaf";
  "code": 200,
  "msg": "sucess"
  }