Ошибка при подключении к лазурным источникам данных с использованием токена продолжения - PullRequest
0 голосов
/ 22 мая 2019

В настоящее время я пытаюсь создать список файлов / каталогов внутри adls2, используя маркер продолжения (в настоящее время наша папка содержит более 5000 файлов). Я могу отправить свой первый запрос, однако получаю сообщение об ошибке 403 (предположительно, означающее неправильное форматирование) при попытке установить соединение с маркером продолжения в ответе и не уверен, какие проблемы с форматированием могли быть причиной этой ошибки.

В настоящее время я пытался удалить знак = в конце ключа для URI, поскольку это было проблемой для кого-то другого. Я также безуспешно пытался создать заголовок для продолжения внутри моего запроса.

adls_request является основной функцией. Это выполняется дважды, один раз для первоначального запроса, второй для продолжения. В настоящее время у меня установлено продолжение внутри URI и подписи.

def gen_signature(request_time, api_version, storage_account_name, file_system_name, storage_account_key, signature_params):
    string_params = {
        'verb': 'GET',
        'Content-Encoding': '',
        'Content-Language': '',
        'Content-Length': '',
        'Content-MD5': '',
        'Content-Type': '',
        'Date': '',
        'If-Modified-Since': '',
        'If-Match': '',
        'If-None-Match': '',
        'If-Unmodified-Since': '',
        'Range': '',
        'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-version:' + api_version,
        'CanonicalizedResource': '/' + storage_account_name+'/'+file_system_name+signature_params
        }

    string_to_sign = (string_params['verb'] + '\n' 
                      + string_params['Content-Encoding'] + '\n'
                      + string_params['Content-Language'] + '\n'
                      + string_params['Content-Length'] + '\n'
                      + string_params['Content-MD5'] + '\n' 
                      + string_params['Content-Type'] + '\n' 
                      + string_params['Date'] + '\n' 
                      + string_params['If-Modified-Since'] + '\n'
                      + string_params['If-Match'] + '\n'
                          + string_params['If-None-Match'] + '\n'
                      + string_params['If-Unmodified-Since'] + '\n'
                      + string_params['Range'] + '\n'
                      + string_params['CanonicalizedHeaders']+'\n'
                      + string_params['CanonicalizedResource'])

    signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
    return signed_string

def create_headers(request_time, api_version, storage_account_name, signed_string):
    headers = {
        'x-ms-date' : request_time,
        'x-ms-version' : api_version,
        'Authorization' : ('SharedKey ' + storage_account_name + ':' + signed_string)
    }
    return headers

def create_url(storage_account_name, file_system_name, url_params):
    url = ('https://' + storage_account_name + '.dfs.core.windows.net/'+file_system_name+url_params)
    return url

def set_optional_params(list_dir, file_dir, token_continuation):
    if token_continuation != '':
        token_continuation_sig = '\ncontinuation:'+token_continuation
        token_continuation_url = '&continuation='+token_continuation[:-1]
    else:
        token_continuation_sig = ''
        token_continuation_url = ''
    print token_continuation_sig
    print token_continuation_url

    if list_dir:
        print type(token_continuation)
        signature_params = '\ndirectory:'+file_dir+'\nrecursive:true'+token_continuation_sig+'\nresource:filesystem'
        url_params = '?directory='+file_dir+'&recursive=true'+token_continuation_url+'&resource=filesystem'
        return signature_params, url_params
    else:
        signature_params = ''
        url_params = ''
        return signature_params, url_params


def get_request_time():
    return datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')


def adls_request(list_dir,
                 file_system_name,
                 file_dir  = '',
                 storage_account_name = 'account_name',
                 storage_account_key = '123456789==',
                 api_version = '2018-11-09',
                 token_continuation = ''):

    signature_params, url_params = set_optional_params(list_dir, file_dir, token_continuation)
    request_time = get_request_time()
    signature = gen_signature(request_time, api_version, storage_account_name, file_system_name, storage_account_key, signature_params)
    headers = create_headers(request_time, api_version, storage_account_name, signature)
    url = create_url(storage_account_name, file_system_name, url_params)
    r = requests.get(url, headers = headers)
    return r

Я ожидаю, что выходной ответ получит 200, содержащий остальные файлы в каталоге, но все еще в настоящее время получает ошибку 403.

1 Ответ

0 голосов
/ 24 мая 2019

Пожалуйста, попробуйте код ниже, я использую Python 3.7 для теста:

import requests
import datetime
import hmac
import hashlib
import base64
import urllib.parse

def gen_signature(request_time, api_version, storage_account_name, file_system_name, storage_account_key, signature_params):    
    string_params = {
        'verb': 'GET',
        'Content-Encoding': '',
        'Content-Language': '',
        'Content-Length': '',
        'Content-MD5': '',
        'Content-Type': '',
        'Date': '',
        'If-Modified-Since': '',
        'If-Match': '',
        'If-None-Match': '',
        'If-Unmodified-Since': '',
        'Range': '',
        'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-version:' + api_version,
        'CanonicalizedResource': '/' + storage_account_name + '/' + file_system_name + signature_params,
        }

    string_to_sign = (string_params['verb'] + '\n' 
                      + string_params['Content-Encoding'] + '\n'
                      + string_params['Content-Language'] + '\n'
                      + string_params['Content-Length'] + '\n'
                      + string_params['Content-MD5'] + '\n' 
                      + string_params['Content-Type'] + '\n' 
                      + string_params['Date'] + '\n' 
                      + string_params['If-Modified-Since'] + '\n'
                      + string_params['If-Match'] + '\n'
                      + string_params['If-None-Match'] + '\n'
                      + string_params['If-Unmodified-Since'] + '\n'
                      + string_params['Range'] + '\n'
                      + string_params['CanonicalizedHeaders']+'\n'
                      + string_params['CanonicalizedResource'])

    signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
    return signed_string

def create_headers(request_time, api_version, storage_account_name, signed_string):
    headers = {
        'x-ms-date' : request_time,
        'x-ms-version' : api_version,
        'Authorization' : ('SharedKey ' + storage_account_name + ':' + signed_string)
    }
    return headers

def create_url(storage_account_name, file_system_name, url_params):
    url = ('https://' + storage_account_name + '.dfs.core.windows.net/'+file_system_name+url_params)
    return url

def set_optional_params(list_dir, file_dir, token_continuation):
    if token_continuation != '':
        token_continuation_sig = '\ncontinuation:'+ token_continuation

        #Note that since the continuation token ended with =, you should encode the token, then add to url.
        token_continuation_url = '&continuation='+urllib.parse.quote_plus(token_continuation)  
    else:
        token_continuation_sig = ''
        token_continuation_url = ''
    #print(token_continuation_sig)
    #print(token_continuation_url)

    if list_dir:
        if token_continuation !='':
            signature_params = token_continuation_sig + '\ndirectory:' + file_dir + '\nrecursive:true' + '\nresource:filesystem'
            url_params = '?directory=' + file_dir + '&recursive=true' + token_continuation_url + '&resource=filesystem'
            return signature_params, url_params
        else:
            signature_params =  '\ndirectory:' + file_dir + '\nrecursive:true' + '\nresource:filesystem'
            url_params = '?directory=' + file_dir + '&recursive=true' + '&resource=filesystem'
            return signature_params, url_params
    else:
        signature_params = ''
        url_params = ''
        return signature_params, url_params


def get_request_time():
    return datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')


def adls_request(list_dir,
                 file_system_name,
                 file_dir  = '',
                 storage_account_name = 'account_name',
                 storage_account_key = '123456789==',
                 api_version = '2018-11-09',
                 token_continuation = ''):

    signature_params,url_params = set_optional_params(list_dir, file_dir, token_continuation)

    request_time = get_request_time()
    signature = gen_signature(request_time, api_version, storage_account_name, file_system_name, storage_account_key, signature_params)
    headers = create_headers(request_time, api_version, storage_account_name, signature)
    url = create_url(storage_account_name, file_system_name, url_params)    
    print(url)
    r = requests.get(url, headers = headers)
    return r

if __name__ == '__main__':
    list_dir = True
    file_system_name ="dd1"
    file_dir="testfile"
    storage_account_name = 'xxx'
    storage_account_key = 'xxxx'
    api_version = '2018-11-09'
    token_continuation = ''
    print("******First Time without continuation token******")
    #The 1st time to get files which can be up to 5000
    r = adls_request(list_dir,file_system_name,file_dir,storage_account_name,storage_account_key,api_version,token_continuation)
    print(r)

    print("\n\n******Sencond Time with continuation token******")
    #Then 2nd time to get files with continuation token
    #when files are more than 5000, you will get a continuation token
    if 'x-ms-continuation' in r.headers:
        token_continuation=r.headers["x-ms-continuation"]
        print("continuation token: "+token_continuation)

    r = adls_request(list_dir,file_system_name,file_dir,storage_account_name,storage_account_key,api_version,token_continuation)
    print(r)

Результат теста:

enter image description here

У меня есть 6000 файлов в каталоге, и обратите внимание, что если вы получаете токен продолжения (если файлов в каталоге больше 5000, в противном случае токен не возвращается), вы должны закодировать токен, а затем добавить закодированный токен в URL .

Это простой тест, и, пожалуйста, не стесняйтесь изменять код в соответствии с вашими потребностями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...