京东云最新签名算法

import datetime
import time
import hashlib
import hmac
import re
import uuid

import sys
import base64
import re
if sys.version_info.major == 2:
    from urllib import quote # 遵循RFC 2396
    from urllib import quote_plus # /会进行编码
    from urllib import unquote
    from urllib import unquote_plus # +会解码为空格
    from urlparse import urlparse
elif sys.version_info.major == 3:
    from urllib.parse import quote # 遵循RFC 2396
    from urllib.parse import quote_plus # /会进行编码
    from urllib.parse import unquote
    from urllib.parse import unquote_plus # +会解码为空格
    from urllib.parse import urlparse


# base64 encode
def base64encode(value):
    if sys.version_info.major == 2:
        return base64.b64encode(value)
    elif sys.version_info.major == 3:
        encoded_value = base64.b64encode(value.encode('utf-8'))
        return str(encoded_value, 'utf-8')


# byte to string
def byte_to_str(string):
    if sys.version_info.major == 2:
        return string
    elif sys.version_info.major == 3:
        return str(string, 'utf-8')


# parse url
def parse_url(url):
    scheme, netloc, path, params, query, fragment = urlparse(url)
    pattern = (r'^'
               r'((?P<user>.+?)(:(?P<password>.*?))?@)?'
               r'(?P<host>.*?)'
               r'(:(?P<port>\d+?))?'
               r'$')
    regex = re.compile(pattern)
    match = regex.match(netloc)
    group_dict = match.groupdict() if match is not None else None
    if path is None:
        path = '/'
    if query is None:
        query = ''
    group_dict['path'] = path
    group_dict['schema'] = scheme
    group_dict['query'] = query
    group_dict['fragment'] = fragment
    return group_dict


class Signer(object):
    ignored_headers = ['authorization', 'user-agent']

    def sign(self, method, service, region, uri, headers, data, credential, security_token):
        uri_dict = self.__url_path_to_dict(uri)
        host = uri_dict['host']
        port = uri_dict['port']
        path = uri_dict['path']
        query = uri_dict['query']

        if port and port not in ['80', '443']:
            full_host = host + ':' + port
        else:
            full_host = host
        return self.signV3(method, service, region, full_host, path, query, headers, data, credential, security_token)

    def signV3(self, method, service, region, host, path, query, headers, data, credential, security_token):
        canonical_host = self.__build_canonical_host(host)
        now = self.__now()
        nonce = str(uuid.uuid4())
        jdcloud_date = now.strftime('%Y%m%dT%H%M%SZ')
        if "x-jdcloud-date" in headers:
            jdcloud_date = headers["x-jdcloud-date"]
        if 'x-jdcloud-nonce' in headers:
            nonce = headers['x-jdcloud-nonce']
        date_str = jdcloud_date[:8]

        canonical_querystring = self.__normalize_query_string(query)
        canonical_headers, signed_headers = self.__build_canonical_headers(headers, security_token, canonical_host)

        payload_hash = self.__sha256_hash(data)

        canonical_request = (method + '\n' +
                             self.__build_canonical_uri(path) + '\n' +
                             canonical_querystring + '\n' +
                             canonical_headers + '\n' +
                             signed_headers + '\n' +
                             payload_hash)

        algorithm = 'JDCLOUD2-HMAC-SHA256'
        credential_scope = (date_str + '/' +
                            region + '/' +
                            service + '/' +
                            'jdcloud2_request')
        string_to_sign = (algorithm + '\n' +
                          jdcloud_date + '\n' +
                          credential_scope + '\n' +
                          self.__sha256_hash(canonical_request))

        print('---canonical_request---\n' + canonical_request)
        print('----string_to_sign---\n' + string_to_sign)

        signing_key = self.__get_signature_key(credential.secret_key, date_str, region, service)
        encoded = string_to_sign.encode('utf-8')
        signature = hmac.new(signing_key, encoded, hashlib.sha256).hexdigest()

        print("credential_scope; ", credential_scope)

        authorization_header = (
                algorithm + ' ' +
                'Credential=' + credential.access_key + '/' + credential_scope + ', ' +
                'SignedHeaders=' + signed_headers + ', ' +
                'Signature=' + signature
        )

        headers.update({
            'Authorization': authorization_header,
            "x-jdcloud-date": jdcloud_date,
            'x-jdcloud-content-sha256': payload_hash,
            'JDCLOUD2-HMAC-SHA256': 'JDCLOUD2-HMAC-SHA256',
            'x-jdcloud-nonce': nonce
        })

        if security_token:
            headers.update({'x-jdcloud-security-token': security_token})

    def __build_canonical_host(self, full_host):
        if full_host.lower().find('http://') == 0:
            full_host = full_host[7:]
        elif full_host.lower().find('https://') == 0:
            full_host = full_host[8:]
        return full_host

    def __normalize_query_string(self, query):
        params = []
        if isinstance(query, str):
            for s in query.split('&'):
                if len(s) <= 0:
                    continue
                list = []
                for val in s.split('='):
                    list.append(self.__urlencode(self.__urldecode(val)))
                params.append(list)
        elif isinstance(query, dict):
            for key in query.keys():
                list = []
                list.append(self.__urlencode(self.__urldecode(key)))
                list.append(self.__urlencode(self.__urldecode(query[key])))
                params.append(list)

        normalized = ''
        for p in sorted(params):
            if p[0] == '':
                continue
            elif len(p) == 2:
                normalized += '%s=%s&' % (p[0], p[1])
            elif len(p) > 2:
                normalized += '%3D'.join(p[1:]) + '&'
        if normalized.endswith('&'):
            normalized = normalized[:normalized.__len__()-1]
        return normalized

    def __now(self):
        return datetime.datetime.utcfromtimestamp(time.time())

    def __url_path_to_dict(self, path):
        """http://stackoverflow.com/a/17892757/142207"""

        # pattern = (r'^'
        #            r'((?P<schema>.+?)://)?'
        #            r'((?P<user>.+?)(:(?P<password>.*?))?@)?'
        #            r'(?P<host>.*?)'
        #            r'(:(?P<port>\d+?))?'
        #            r'(?P<path>/.*?)?'
        #            r'(\?(?P<query>.*?))?'
        #            r'$')
        # regex = re.compile(pattern)
        # match = regex.match(path)
        # group_dict = match.groupdict() if match is not None else None
        #
        # if group_dict['path'] is None:
        #     group_dict['path'] = '/'
        #
        # if group_dict['query'] is None:
        #     group_dict['query'] = ''
        # return group_dict
        return parse_url(path)

    def __sign(self, key, msg):
        return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

    def __get_signature_key(self, key, date_stamp, region_name, service_name):
        JDCLOUD2 = 'JDCLOUD2'
        JDCLOUD2_REQUEST = 'jdcloud2_request'
        k_date = self.__sign((JDCLOUD2 + key).encode('utf-8'), date_stamp)
        k_region = self.__sign(k_date, region_name)
        k_service = self.__sign(k_region, service_name)
        k_signing = self.__sign(k_service, JDCLOUD2_REQUEST)
        return k_signing

    def __sha256_hash(self, val):
        return hashlib.sha256(val.encode('utf-8')).hexdigest()

    def __build_canonical_uri(self, path):
        reg = re.compile('/+')
        decoded_path = reg.sub('/', self.__urldecode(path))
        if decoded_path == '':
            return '/'
        encoded_path = self.__urlencode_ignore_slashes(decoded_path)
        if encoded_path.startswith('/'):
            return encoded_path
        return '/' + encoded_path

    def __urlencode(self, value):
        return quote(value, '~')

    def __urlencode_ignore_slashes(self, value):
        return quote(value, '/~')

    def __urldecode(self, value):
        return unquote_plus(value)

    def __build_canonical_headers(self, req_headers, security_token, full_host):
        headers = ['host']  # add host header first
        signed_values = {}

        for key in req_headers.keys():
            value = req_headers[key]

            lower_key = key.lower()
            if lower_key in Signer.ignored_headers:
                continue

            headers.append(lower_key)
            signed_values[lower_key] = value

        headers.sort()
        signed_headers = ';'.join(headers)

        canonical_values = []
        for key in headers:
            if key == 'host':
                canonical_values.append('host:' + full_host.strip())
            else:
                # canonical_values.append(key + ':' + )
                header_value = signed_values[key]
                if isinstance(header_value, str):
                    canonical_values.append(key + ':' + header_value.strip())
                elif isinstance(header_value, list):
                    arr = []
                    for val in header_value:
                        arr.append(val.strip())
                    canonical_values.append(key + ':' + ','.join(arr))


        canonical_headers = '\n'.join(canonical_values) + '\n'

        return canonical_headers, signed_headers


if __name__ == '__main__':
    import requests
    from jdcloud_sdk.core.credential import Credential
    region = 'cn-north-1'
    header = {'Content-Type': 'application/json'}
    body = ""
    method = "POST"
    token = ""
    service_name = "cp"


    url ="这里填你需要的路由"
    print('url=',url)
    access_key = ''
    secret_key = ''
    credential = Credential(access_key, secret_key)

    signer = Signer()
    signer.sign(method="POST", region=region, uri=url,
                headers=header, data=body, credential=credential,
                security_token=token, service=service_name)
    print("header; ", header)

    response = requests.request(method, url, data=body, headers=header, timeout=20)

    # 处理响应
    if response.status_code == 200:
        data = response.json()
        # 处理返回的数据
        print(data)
    else:
        print("请求失败:", response.text)


  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值