对Dynamics客户参与Web API的应用程序权限支持

时间:2019-08-12 14:36:50

标签: dynamics-crm dynamics-crm-online dynamics-365

我们正计划从“组织服务”迁移到Common Data Service Web API,以便我们可以利用OAuth 2.0身份验证来代替客户担心一些安全问题的服务帐户。

一旦我们做了一些原型,我们发现Web API身份验证与典型的Graph API身份验证有些不同。它仅支持委派权限。因此,必须提供用户凭证以获取访问令牌。

这是CRM Web API的Azure AD Graph API权限: enter image description here

这是在Web API Global Discovery Service Sample (C#)

处获取示例代码的访问令牌的代码
  string GlobalDiscoUrl = "https://globaldisco.crm.dynamics.com/";
  AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com", false);

  UserCredential cred = new UserCredential(username, password);
  AuthenticationResult authResult = authContext.AcquireToken(GlobalDiscoUrl, clientId, cred);

这里还有另一篇类似的帖子Connect to Dynamics 365 Customer Engagement web services using OAuth,尽管它已经存在了一年多。

您知道MS何时会支持“应用程序”权限以完全消除用户的身份验证吗?还是有任何特殊原因使用户留在这里。感谢您的任何见解。

[更新1 ] 在James的以下答复中,我对代码进行了修改,这是我的代码

        string clientId = "3f4b24d8-61b4-47df-8efc-1232a72c8817";
        string secret = "xxxxx";

        ClientCredential cred = new ClientCredential(clientId, secret);
        string GlobalDiscoUrl = "https://globaldisco.crm.dynamics.com/";
        AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/common", false);


        AuthenticationResult authResult = authContext.AcquireToken(GlobalDiscoUrl, cred);

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
        client.Timeout = new TimeSpan(0, 2, 0);
        client.BaseAddress = new Uri(GlobalDiscoUrl);

        HttpResponseMessage response = client.GetAsync("api/discovery/v1.0/Instances", HttpCompletionOption.ResponseHeadersRead).Result;


        if (response.IsSuccessStatusCode)
        {
            //Get the response content and parse it.
            string result = response.Content.ReadAsStringAsync().Result;
            JObject body = JObject.Parse(result);
            JArray values = (JArray)body.GetValue("value");

            if (!values.HasValues)
            {
                return new List<Instance>();
            }

            return JsonConvert.DeserializeObject<List<Instance>>(values.ToString());
        }
        else
        {
            throw new Exception(response.ReasonPhrase);
        }
    }

因此我能够获取访问令牌,但是它仍然无法访问全局发现服务。

访问令牌如下所示:

    {
  "aud": "https://globaldisco.crm.dynamics.com/",
  "iss": "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",
  "iat": 1565802457,
  "nbf": 1565802457,
  "exp": 1565806357,
  "aio": "42FgYEj59uDNtwvxTLnprU0NYt49AA==",
  "appid": "3f4b24d8-61b4-47df-8efc-1232a72c8817",
  "appidacr": "1",
  "idp": "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",
  "tid": "f8cdef31-a31e-4b4a-93e4-5f571e91255a",
  "uti": "w8uwKBSPM0y7tdsfXtAgAA",
  "ver": "1.0"
}

顺便说一句,我们已经按照说明在CRM内部创建了应用程序用户。

我在这里想念什么吗?

[更新2 ] 对于WhoAmI请求,会有不同的结果。如果我使用最新的MSAL并具有“ https://login.microsoftonline.com/AzureADDirectoryID/oauth2/authorize”权限,则可以得到正确的结果。如果我将MSAL与“ https://login.microsoftonline.com/common/oauth2/authorize”一起使用,它将无法正常工作,我会得到未授权的错误。如果我使用的是ADAL 2.29,则这两种权限均无效。这是工作代码:

            IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create("3f4b24d8-61b4-47df-8efc-1232a72cxxxx")
            .WithClientSecret("xxxxxx")
          //  .WithAuthority("https://login.microsoftonline.com/common/oauth2/authorize", false)  
            .WithAuthority("https://login.microsoftonline.com/3a984a19-7f55-4ea3-a422-2d8771067f87/oauth2/authorize", false)
            .Build();

        var authResult = app.AcquireTokenForClient(new String[] { "https://crmxxxxx.crm5.dynamics.com/.default" }).ExecuteAsync().Result;

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
        client.Timeout = new TimeSpan(0, 2, 0);
        client.BaseAddress = new Uri("https://crm525842.api.crm5.dynamics.com/");

        HttpResponseMessage response = client.GetAsync("api/data/v9.1/WhoAmI()", HttpCompletionOption.ResponseHeadersRead).Result;


        if (response.IsSuccessStatusCode)
        {
            //Get the response content.
            string result = response.Content.ReadAsStringAsync().Result;
            Console.WriteLine(result);
        }
        else
        {
            throw new Exception(response.ReasonPhrase);
        }

1 个答案:

答案 0 :(得分:1)

该文档并不是最容易遵循的文档,但是据我了解,您应该从Use OAuth with Common Data Service开始。

注册应用程序时,您有两个微妙的选择。第二个不需要Access Dynamics 365 /公共数据服务作为组织用户权限

Giving access to Common Data Service

  

如果您的应用将是允许经过身份验证的用户执行以下操作的客户端   执行操作,您必须将应用程序配置为具有   作为组织用户的委派权限访问Dynamics 365。

  

如果您的应用将使用服务器到服务器(S2S)身份验证,请执行此步骤   不需要。该配置需要特定的系统用户   并且操作将由该用户帐户执行,而不是   任何必须通过身份验证的用户。

这将进一步详细说明。

Connect as an app

  

您将要创建的某些应用并非旨在由以下用户交互式运行   用户。在这些情况下,您可以创建一个特殊的应用程序用户   绑定到Azure Active Directory注册的应用程序,并且   使用为应用程序配置的密钥机密或上载X.509   证书。这种方法的另一个好处是它不会   消费付费许可证。

     

注册您的应用

     

注册应用程序时,请执行许多相同的步骤...   以下例外:

     
      
  • 您不需要授予Access Dynamics 365作为组织用户的权限
  •   

您将在Dynamics中仍然有一个系统用户记录,以代表应用程序注册。这支持一系列基本的Dynamics行为,并允许您将Dynamics安全性应用于您的应用。

与用户名和密码相反,您可以使用密码进行连接。

string serviceUrl = "https://yourorg.crm.dynamics.com";
string clientId = "<your app id>";
string secret = "<your app secret>";

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

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

string accessToken = result.AccessToken;

或证书。

string CertThumbPrintId = "DC6C689022C905EA5F812B51F1574ED10F256FF6";
string AppID = "545ce4df-95a6-4115-ac2f-e8e5546e79af";
string InstanceUri = "https://yourorg.crm.dynamics.com";

string ConnectionStr = $@"AuthType=Certificate;
                        SkipDiscovery=true;url={InstanceUri};
                        thumbprint={CertThumbPrintId};
                        ClientId={AppID};
                        RequireNewInstance=true";
using (CrmServiceClient svc = new CrmServiceClient(ConnectionStr))
{
    if (svc.IsReady)
    {
    ...
    }
}

您可能还想查看Build web applications using Server-to-Server (S2S) authentication,它看起来很相似(但不同)。

  

使用服务器到服务器(S2S)身份验证来安全无缝地进行   通过您的Web应用程序与Common Data Service通信,并且   服务。 S2S身份验证是应用程序在其上注册的常用方法   Microsoft AppSource用于访问的通用数据服务数据   他们的订户。 ...而不是用户凭据,而是基于存储在应用程序用户记录中的Azure AD对象ID值标识的服务主体对应用程序进行身份验证。

放在一边;如果您当前正在使用Organization Service .NET对象,那么该对象将在内部迁移到使用Web API。

Microsoft Dynamics CRM 2011 endpoint

  

Dynamics 365 SDK程序集将更新为使用Web API。   此更新对您和任何编写的代码完全透明   将支持使用SDK本身。