繁体   English   中英

如何使用 Python 连接到 Microsoft Dataverse API 端点

[英]How to connect to Microsoft Dataverse API Endpoint with Python

我在通过 Python 连接到 Microsoft Dataverse API 端点时遇到问题。

代码分为三部分:

A) 代币生成

B) 端点 API 调用选项 1

C) 端点 API 调用选项 2

################ Token generation code begins ################
import adal

# Tenant ID for your Azure Subscription
TENANT_ID = 'abc'
# Your Service Principal App ID
CLIENT = '52'
# Your Service Principal Password
KEY = '43'


# subscription_id = 'xxxxxxx'

authority_url = 'https://login.microsoftonline.com/'+TENANT_ID
context = adal.AuthenticationContext(authority_url)
token = context.acquire_token_with_client_credentials(
    resource='https://orgabc.api.crm8.dynamics.com/',
    client_id=CLIENT,
    client_secret=KEY
)

print('Fresh token is: ', token["accessToken"])
print('Full response is: ', token)

################ Token generation code ends ################

################ Method/Option 1: Token generation code begins ################
import requests
import json
import msal
config = {
    "authority": "https://login.microsoftonline.com/abc",
    "client_id": "52",
    "client_secret": "43",
    "scope": ["https://orgabc.crm8.dynamics.com/.default"],
}
app = msal.ConfidentialClientApplication(
    config["client_id"],
    authority=config["authority"],
    client_credential=config["client_secret"])
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
    result = app.acquire_token_for_client(scopes=config["scope"])
# bearerToken = result['access_token']
bearerToken = token["accessToken"]
url = "https://orgabc.api.crm8.dynamics.com/api/data/v9.2"
headers = {
    "Accept": "application/json",
    "Content-type": "application/json",
    "Authorization": "Bearer "+bearerToken,
}

response = requests.request("GET", url, headers = headers)
print(response)
################ Method/Option 1: Token generation code ends ################


# ################ Method/Option 2: Token generation code begins ################
# import requests
# import json
#
# # set these values to retrieve the oauth token
# crmorg = 'https://orgabc.crm8.dynamics.com'  # base url for crm org
# clientid = '52'  # application client id
# username = 'xyz@example.onmicrosoft.com'  # username
# userpassword = 'HgN@6013'  # password
# tokenendpoint = 'https://login.microsoftonline.com/abc/oauth2/v2.0/token'  # oauth token endpoint
#
# # set these values to query your crm data
# crmwebapi = 'https://orgabc.crm8.dynamics.com/api/data/v9.2'  # full path to web api endpoint
# # crmwebapiquery = '/contacts?$select=fullname,contactid'  # web api query (include leading /)
# crmwebapiquery = '/accounts'  # web api query (include leading /)
#
#
# # build the authorization token request
# tokenpost = {
#     'client_id': clientid,
#     'resource': crmorg,
#     'username': username,
#     'password': userpassword,
#     'grant_type': 'password'
# }
#
# # make the token request
# tokenres = requests.post(tokenendpoint, data=tokenpost)
#
# # set accesstoken variable to empty string
# accesstoken = ''
#
# # extract the access token
# try:
#     accesstoken = token["accessToken"]
# except(KeyError):
#     # handle any missing key errors
#     print('Could not get access token')
#
# # if we have an accesstoken
# if (accesstoken != ''):
#     # prepare the crm request headers
#     crmrequestheaders = {
#         'Authorization': 'Bearer ' + token["accessToken"],
#         'OData-MaxVersion': '4.0',
#         'OData-Version': '4.0',
#         'Accept': 'application/json',
#         'Content-Type': 'application/json; charset=utf-8',
#         'Prefer': 'odata.maxpagesize=500',
#         'Prefer': 'odata.include-annotations=OData.Community.Display.V1.FormattedValue'
#     }
#
#     # make the crm request
#     crmres = requests.get(crmwebapi + crmwebapiquery, headers=crmrequestheaders)
#
#     try:
#         # get the response json
#         crmresults = crmres.json()
#
#         # loop through it
#         for x in crmresults['value']:
#             print(x['fullname'] + ' - ' + x['contactid'])
#     except KeyError:
#         # handle any missing key errors
#         print('Could not parse CRM results')
# ################ Method/Option 2: Token generation code ends ################

代码的块 1 工作正常,我们正在生成令牌,但是当我们尝试块 2 或 3 时,在这两种情况下代码都失败并出现以下错误(完整回溯):

Traceback (most recent call last):
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\connectionpool.py", line 597, in urlopen
    httplib_response = self._make_request(conn, method, url,
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request
    self._validate_conn(conn)
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\connectionpool.py", line 849, in _validate_conn
    conn.connect()
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\connection.py", line 349, in connect
    self.sock = ssl_wrap_socket(
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\util\ssl_.py", line 359, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "C:\Users\aakashbasu1\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "C:\Users\aakashbasu1\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1040, in _create
    self.do_handshake()
  File "C:\Users\aakashbasu1\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\requests\adapters.py", line 440, in send
    resp = conn.urlopen(
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\connectionpool.py", line 637, in urlopen
    retries = retries.increment(method, url, error=e, _pool=self,
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\urllib3\util\retry.py", line 398, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='orgabc.api.crm8.dynamics.com', port=443): Max retries exceeded with url: /api/data/v9.2 (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)')))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\internal_experiments\azure_ad_token_generator.py", line 60, in <module>
    response = requests.request("GET", url, headers = headers)
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\requests\api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\requests\sessions.py", line 529, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\requests\sessions.py", line 645, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\aakashbasu1\PycharmProjects\Personal_RnD\venv\lib\site-packages\requests\adapters.py", line 517, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='orgabc.api.crm8.dynamics.com', port=443): Max retries exceeded with url: /api/data/v9.2 (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)')))

对于 Dataverse 的这个问题,开放论坛上没有太多帮助。 有一个可用的 C# 代码可以正常工作,但我们需要使用 Python。 相同的 C# 代码是:

using Microsoft.AspNetCore.Http;
using Microsoft.Graph;
using Microsoft.WindowsAzure.ActiveDirectory.Authentication;
using MySql.Data.MySqlClient.Memcached;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;

namespace AccessToken
{
    class Program
    {
        static void Main(string[] args)
        {
            string serviceUrl = "https://orgabc.crm8.dynamics.com";
            string clientId = "52";//"<your app id>";
            string secret = "41";//"<your app secret>";

            AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/53");//tenant ID 
            ClientCredential credential = new ClientCredential(clientId, secret);

            AuthenticationResult result = authContext.AcquireToken(serviceUrl,credential);

            string accessToken = result.AccessToken;
            Console.WriteLine("Hello World!");
            Console.WriteLine("Acces Token for given :"+accessToken);

            //Retrieving data here
            using (var client = new HttpClient())
            {
               
                var tokenType = "Bearer"; //Other APIs use Bearer or other auth types.
                
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);//token type=Bearer, accesstoken refers to token which we generated.
                //https://orgabc.crm8.dynamics.com refers to org URL

                var content = client.GetStringAsync("https://orgabc.crm8.dynamics.com/api/data/v9.2/accounts");//accounts refers to the User Table Logical Name.
                Console.WriteLine("Acces Token for given :" + content.Result);

            }
            //end of retrieve data.
        }
    }
}

我们尝试了什么?

  • 根据微软文档将 API 版本从实际的 9.2 更改为 9.1 和 9.0
  • 根据多个这样的 SO Q/A 的建议降低 urllib 版本
  • 使用 Postman Tool 处理相同的连接细节非常好

因此,缩小范围似乎问题在于代码到达端点。 有什么帮助吗?

该代码没有错误,它是正确编写的。 问题在于本地计算机的防火墙/代理/VPN 设置问题,它阻止了实际的 API 调用。 在开放系统上运行时它工作正常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM