小米帐号OAuth 2.0互通接口应用学习

来源:互联网 发布:linux安装gcc 编辑:程序博客网 时间:2024/04/29 18:11

最近,在做一个和小米账号互通的第三方登陆接口,详细的学习了小米开发者文档,下面对接口文档的学习进行总结和汇总。

1.相关名词的解释

  • 服务提供方(resource server): 用户使用服务提供方来存储受保护的资源,这里指的是小米公司。
  • 用户(user):存放在服务提供方的受保护的资源的拥有者。
  • 客户端(client):要访问服务提供方资源的第三方应用,通常是网站在认证过程之前,客户端要向服务提供者申请客户端标识。
  • 令牌(token):分发给客户端的代表访问授权的字符串。通常这个字符串对客户端来说是不透明的。令牌代表资源拥有者许可的访问作用域和持续时间,并由资源服务器和授权服务器强制保证。这个令牌可以代表一个标识符,用于检索授权信息,或以一种可验证的方式自包含授权信息(即一个包含数据和签名的令牌字符串)。令牌可能只代表纯粹的访问能力。
  • 访问令牌(access token):客户端用来代表资源拥有者发送验证请求的令牌。 小米API将支持OAuth 2.0中Bearer Token和MAC Token的两种token形式。
  • 刷新令牌(refresh token):客户端用来获取新的访问令牌的令牌,而不用资源拥有者的参与。
  • 授权码(code):一个短期令牌,代表终端用户的授权。授权码用于获取一个访问令牌和一个刷新令牌。
  • 客户端标识符(client id):分发给客户端的唯一标识,用于客户端向授权服务器标识自己。客户端标识符可以有一个对应的密钥。

2.授权接口说明

授权码方式(authorization code)获取访问令牌(access token)的授权验证流程又被称为web server flow,适用于所有有服务端的应用,如Web/Wap站点、有服务端的手机/桌面客户端应用等。
这里写图片描述

2.1请求用户授权接口

  • URL: https://account.xiaomi.com/oauth2/authorize
  • HTTP请求方: GET
    请求用户授权参数表
名称 必须 范围 说明 client_id true Long 申请应用时分配的App Id。 redirect_uri true String 授权回调地址,必须和申请应用是填写的一致。 response_type true String 描述获取授权的方式,目前只支持code 和 token,Code 对应 Authorization Code true String Flow, token对应Implicit Flow。 scope false String 申请scope权限所需参数,可一次申请多个scope权限,用空格分隔。 state false String 用于保持请求和回调的状态,在回调时,会在Query Parameter中回传该参数。 skip_confirm false Boolean 是否跳过帐号确认过程,黄页接入请设置为true(skip_confirm=true)

接口返回值
response_type为code(Authorization Code Flow)时接口返回值:

名称 必须 范围 说明 code True String 用于调用access_token,接口获取授权后的access token。 state False String 如果请求时传递参数,会回传该参数。

2.2 获取访问令牌接口

  • URL : http://account.xiaomi.com/oauth2/token
  • HTTP请求方式: GET
    获取访问令牌参数表
名称 必须 范围 说明 client_id True Long 申请应用时分配的App Id。 redirect_uri True String 授权回调地址,必须和申请应用是填写的一致。 client_secret True String 申请应用时分配的App Secret grant_type True String 此值为authorization_code 或者 refresh_token refresh_token False String 当grant_type为refresh_token时,必须传该参数,置为上次下发的 code False String 当grant_type为authorization_code时,必须传该参数,置为上次下发的code值 token_type True String 说明返回的token类型,目前是mac

接口返回值
接口返回值是一个Json格式字符串,具体说明如下:
第三方获取访问令牌验证通过,该接口返回Access Token相关的信息:
{
“access_token”: “access token value”,
“expires_in”: 360000,
“refresh_token”: “refresh token value”,
“scope”: “scope value”,
“token_type “: “mac”,
“mac_key “: “mac key value”,
“mac_algorithm”: ” HmacSha1”
“openId”=”2.0XXXXXXXXX”
}
字段说明:
1. access_token:获取的Access Token;
2. expires_in:Access Token的有效期,以秒为单位;
3. refresh_token:用于刷新Access Token ,有效时间为10年;
4. scope:Access Token最终的访问范围,既用户实际授予的权限列表;
5. token_type: access token的类型,type值为mac;
6. mac_key: MAC加密算法对请求进行加密时的密钥;
7. mac_algorithm:MAC加密的算法,目前只支持HmacSha1
8. openId: 是v2版本所提供的一种唯一标识

2.3获取用户名片

  • URL: https://open.account.xiaomi.com/user/profile
  • HTTP请求方式:GET
    获取用户名片参数表
名称 必须 范围 说明 clientId True Long 申请应用时分配的App Id。 token True String 用户授权时client得到的token Header数据 True 详见下文 按照小米提供的算法生成Header授权信息。

返回数据

  • 正确返回:
    如果访问令牌验证通过,会返回用户相关的信息, 返回格式为Json文本, 格式如下:
    {
    “result”: “ok”,
    “description”: “成功”,
    “data”: {
    “miliaoNick”: “米聊昵称”,
    “userId”: 米聊号,
    “miliaoIcon”: 头像URL
    },
    “code”: 0
    }
  • 错误返回
    如果访问令牌验证错误,会返回错误信息, 返回格式为Json文本, 格式如下:
    {
    “result”: “error”,
    “description”: “错误描述”,
    “code”: 错误码
    }

3.Mac Token详细说明

MacToken是授权小米下发的一种访问令牌类型,使用MacToken调用API时,用MAC加密算法对请求进行加密,并将结果放到http请求的header中。MAC算法有HmacSha1和HmacSha256两种,小米API默认使用HmacSha1。
Java算法示例

public static byte[] encryptHMACSha1(byte[] data, byte[] key) {  SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1);  Mac mac = Mac.getInstance(HMAC_SHA1);  mac.init(signingKey);  mac.update(data);  return mac.doFinal();}

PHP算法示例

static public function buildSignature($signString, $secret) {  $sign = base64_encode(hash_hmac('sha1', $signString, $secret, True));  return urlencode($sign);}

3.1请求内容标准化
使用Mac Token需要将请求内容按照一定的规则拼接形成符合要求的标准的格式字符串,标准化字符串用于计算请求API的签名值,小米规定的格式请求字符串格式如下(\n代表换行):
格式化字符串 = Nonce + \n + HTTP方法 + \n + HOST + \n + URI+ \n + QUERY+\n

属性 说明 示例 Nonce 由随机数和时间戳组成,格式:随机数:当前分钟数 HTTP方法 调用API时请求方式 GET/ POST HOST 调用API时的域名 open.account.xiaomi.com URI 调用API时的path(必须以/开头) /user/profile QUERY Key 按照字典序排列的query串,内容为空的去query字段不参与签名 clientId=xxx&token=xxx

具体示例:
请求字符串=54897465748976549:21459478\nGET\n open.account.xiaomi.com\n/user/profile\n
clientId=xxx&token=xxx\n

3.2MacToken请求格式
采用Mac Token调用API,需要将相关签名信息放入请求的http请求的Header中。第三方在发送API请求时,要对请求进行MAC加密计算,并将结果放到请求Header中的”Authorization”字段中。
Authorization字段内容如下:
Authorization: MAC access_token=”token value”,nonce=”随机码” ,mac=”签名值”
字段含义说明:
1. access_token : 授权时下发的access_token。
2. nonce:随机串,由客户端按照2中规则产生的随机字符串包括当前分钟数值。
3. mac:签名值,根据mac算法计算生成的。Mac = HmacSha1(格式化字符串, mac_key)。

相关方法的源代码

static long localTimeDiff = dateDiff(DateTime.Now, getServerTime());static private Random ran = new Random(Dns.GetHostName().GetHashCode()+ (int)DateTime.Now.Ticks);//根据主机名的hashcode和现在时间得到随即种子;/**  * 获取时间差(注意时区)  * @param DateTimeStart时间开始  * @param DateTimeEnd时间结束  * @return 得到时差  */static long dateDiff(DateTime DateTimeStart, DateTime DateTimeEnd){    long dateDiff = 0;    TimeSpan end = new TimeSpan(DateTimeEnd.Ticks);    TimeSpan start = new TimeSpan(DateTimeStart.Ticks);    TimeSpan diff = end.Subtract(start).Duration();    dateDiff = (diff.Days * 24 + diff.Hours);    dateDiff = dateDiff * 60 + diff.Minutes;    Console.WriteLine("get the timediff " + dateDiff);    return dateDiff;}/** * 得到header的值 * @param  nonce为随机数 * @param  mac为mac加密的值 * @param  accessToken为访问令牌 * @return 得到header的值 */static public String createHeader(string nonce, string mac, string accessToken){    string header = string.Format("MAC access_token=\"{0}\",nonce=\"{1}\",mac=\"{2}\"", Uri.EscapeDataString(accessToken), Uri.EscapeDataString(nonce), Uri.EscapeDataString(mac));    return header;}/** * 得到HMACSHA1加密的密文(密文格式为nonce + \n + method(POST\GET) + \n + host + \n + uriPaht + \n + req(queryparam按照key的字典序)+\n(最后也需要添加一个\n)) * @param  nonce为随机数 * @param  query为请求 * @param  method http方法,填“GET”或“POST” * @param  localPath使用参数详情看sdk文档 * @param  macKey,hmacsha1的密钥 * @return 得到HMACSHA1加密的密文 */static public String createCiphertext(string nonce, string query, string method, string localPath, string macKey){    method = method.ToUpperInvariant();    string ciphertext = nonce + "\n" + method + "\n" + XiaoMiHttpClientConst.hostURI + "\n" + localPath + "\n" + query + "\n";    HMACSHA1 hmacsha1 = new HMACSHA1();    hmacsha1.Key = Encoding.UTF8.GetBytes(macKey);    byte[] dataBuffer = Encoding.UTF8.GetBytes(ciphertext);    byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);    ciphertext = Convert.ToBase64String(hashBytes);    return ciphertext;}/*** 得到服务器现在的时间* @param  * @return 得到服务器现在的时间*/static public DateTime getServerTime(){    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(XiaoMiHttpClientConst.apiURI);    request.Method = "GET";    HttpWebResponse response;    Console.WriteLine("waiting for getting the server time");    try    {        response = (HttpWebResponse)request.GetResponse();    }    catch (WebException ex)    {        response = (HttpWebResponse)ex.Response;    }    if (response == null) Console.WriteLine("error: can not get the server time ,please check the network connections");    return response.LastModified;}/* * 得到Nonce用  随机数:时间分钟差 为格式 * @param   * @return Nonce */static public string getNonce(){    //产生随机数过程    int randKey = ran.Next();    string nonce = randKey + ":" + (dateDiff(new DateTime(1970, 1, 1, 8, 0, 0), DateTime.Now) + localTimeDiff);    return nonce;}
0 0
原创粉丝点击