使用OAuth 2.0令牌上传文件至Azure Blob Storage时遇401错误求助
问题:使用OAuth 2.0令牌通过PUT请求上传Azure Blob Storage返回401未授权
我需要将文件上传(后续还需下载)至Azure Blob Storage,但不允许使用Storage SDK,只能用requests、json这类预加载库。目前已经成功拿到OAuth 2.0令牌,但构造PUT请求上传文件时始终返回401错误。
获取令牌的代码能正常返回令牌,而且用Storage SDK可以成功上传文件(说明应用注册和权限配置没问题)。
获取令牌代码:
# Set the request url url = f'https://login.microsoftonline.com/{tenant}/oauth2/token' # Set the request headers headers = {'Content-Type': 'application/x-www-form-urlencoded'} resource = 'https://management.azure.com/' # Set the request body body = { 'grant_type': 'client_credentials', 'client_id': client_id, 'client_secret': client_secret, 'resource': resource } # Make the POST request to the authentication endpoint response = requests.post(url, headers=headers, data=body) # Parse the JSON response response_json = json.loads(response.text) # Save to variable oauth_token = response_json['access_token']
上传文件的PUT请求代码:
# Code to upload file to blob storage # Set the request url endpoint = f'https://{storage_account_name}.blob.core.windows.net/{container_name}/{blob_name}' # Open the file to be uploaded with open(blob_name, "rb") as f: # Get file size file_size = str(len(f.read())) # Get date now = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') # Move the pointer back to the beginning of the file f.seek(0) # Set the headers for the request headers = { "Authorization": f"Bearer {oauth_token}", "x-ms-version":"2020-04-08", "Content-Length": file_size, "x-ms-blob-type": "BlockBlob", "Date": now } # Send the PUT request to upload the file response = requests.put(endpoint, headers=headers, data=f) response.status_code
请求返回状态码为401。我试过加更多请求头字段,也删除重建过应用注册,但还是没法访问资源,求帮忙!
解决方案
你遇到的401问题核心原因是获取OAuth令牌时指定的resource参数不对。
在你的令牌获取代码里,resource设成了https://management.azure.com/,这个资源对应的是Azure管理API的权限,不是Blob存储服务的权限。要访问Blob Storage,得把resource改成https://storage.azure.com/(旧版API也可以用https://<storage-account-name>.blob.core.windows.net/,但前者是通用值更推荐)。
修改后的令牌获取代码:
# Set the request url url = f'https://login.microsoftonline.com/{tenant}/oauth2/token' # Set the request headers headers = {'Content-Type': 'application/x-www-form-urlencoded'} # 修正resource为Blob Storage的资源标识符 resource = 'https://storage.azure.com/' # Set the request body body = { 'grant_type': 'client_credentials', 'client_id': client_id, 'client_secret': client_secret, 'resource': resource } # Make the POST request to the authentication endpoint response = requests.post(url, headers=headers, data=body) # Parse the JSON response response_json = json.loads(response.text) # Save to variable oauth_token = response_json['access_token']
额外优化建议:
- 用
x-ms-date替代Date请求头:Azure Blob Storage API更推荐用x-ms-date指定请求的UTC时间,能避免客户端本地时间设置的潜在问题。修改headers里的Date为x-ms-date:headers = { "Authorization": f"Bearer {oauth_token}", "x-ms-version":"2020-04-08", "Content-Length": file_size, "x-ms-blob-type": "BlockBlob", "x-ms-date": now # 替换原来的Date } - 更高效的文件大小计算方式:当前用
len(f.read())会把整个文件读进内存,大文件场景很不友好,可以改成:
不用打开文件就能获取大小,节省内存。import os file_size = str(os.path.getsize(blob_name))
修改后重新获取令牌再执行上传请求,应该就能解决401的问题了。既然你已经确认应用注册的权限配置没问题(SDK能正常上传),只要令牌的资源匹配,就能通过认证。
内容的提问来源于stack exchange,提问作者Emilio A.
相关产品推荐
相关产品推荐

