签名规范

简介

所有向Xiaomi Cloud-ML服务请求都需要带上请求和签名,客户端签名发送请求后,服务端会重新签名以认证用户身份。

签名算法

签名方法与AWS类似,需要注意签名的参数和顺序。实现签名后需要通过下面的单元测试。

  1. def test_sign(self):
  2. url = 'https://api.github.com/user?a=b'
  3. timestamp = '1474203860'
  4. content_md5 = 'd41d8cd98f00b204e9800998ecf8427e'
  5. app_secret = "sk"
  6. self.assertEquals(
  7. self.signer._sign(url, timestamp, content_md5, app_secret),
  8. '\x10\xe1pv\x96\x1c\x96\xfb\xc7\xe2\x16\x9d\xf4Ma5\x1dO\x86f')
  9. def test_sign_to_base64(self):
  10. url = 'https://api.github.com/user?a=b'
  11. timestamp = '1474203860'
  12. content_md5 = 'd41d8cd98f00b204e9800998ecf8427e'
  13. app_secret = "sk"
  14. self.assertEquals(
  15. self.signer._sign_to_base64(url, timestamp, content_md5, app_secret),
  16. 'EOFwdpYclvvH4had9E1hNR1PhmY=')

Python实现

服务端签名在cloud_ml_common目录中,代码如下。

  1. import base64
  2. import time
  3. import hmac
  4. import hashlib
  5. from hashlib import sha1
  6. from requests.auth import AuthBase
  7. from urllib import unquote
  8. from urlparse import urlparse
  9. from constant import Constant
  10. class Signer(AuthBase):
  11. ''' The signer class used to sign the request. '''
  12. def __init__(self, app_key, app_secret):
  13. self._app_key = str(app_key)
  14. self._app_secret = str(app_secret)
  15. def __call__(self, request):
  16. url = request.url
  17. if not request.body:
  18. request.body = ""
  19. timestamp = request.headers.get(Constant.TIMESTAMP, str(int(time.time())))
  20. content_md5 = request.headers.get(Constant.CONTENT_MD5,
  21. hashlib.md5(request.body).hexdigest())
  22. request.headers[Constant.TIMESTAMP] = timestamp
  23. request.headers[Constant.CONTENT_MD5] = content_md5
  24. request.headers[Constant.AUTHORIZATION] = self._sign_to_base64(
  25. url, timestamp, content_md5, self._app_secret)
  26. request.headers[Constant.SECRET_KEY_ID] = self._app_key
  27. return request
  28. def _sign(self, url, timestamp, content_md5, app_secret):
  29. ''' Sign the specified http request. '''
  30. string_to_sign = "{}\n{}\n{}\n".format(url, timestamp, content_md5)
  31. digest = hmac.new(app_secret, string_to_sign, digestmod=sha1)
  32. return digest.digest()
  33. def _sign_to_base64(self, url, timestamp, content_md5, app_secret):
  34. ''' Sign the specified request to base64 encoded result. '''
  35. signature = self._sign(url, timestamp, content_md5, app_secret)
  36. return base64.encodestring(signature).strip()
  37. def _get_header_value(self, http_headers, name):
  38. if http_headers is not None and name in http_headers:
  39. value = http_headers[name]
  40. if type(value) is list:
  41. return http_headers[name][0]
  42. else:
  43. return value
  44. return ""

原文: http://docs.api.xiaomi.com/cloud-ml/api/signature.html