401- 使用 REST API Dynamics CRM 和 Azure AD 进行未经授权的身份验证

Posted

技术标签:

【中文标题】401- 使用 REST API Dynamics CRM 和 Azure AD 进行未经授权的身份验证【英文标题】:401- Unauthorized authentication using REST API Dynamics CRM with Azure AD 【发布时间】:2016-09-09 23:44:52 【问题描述】:

我正在尝试使用 Azure AD oAuth 2 身份验证访问 Dynamics CRM Online REST API。为此,我遵循了以下步骤: - 我在 Azure 中注册了一个 Web 应用程序和/或 Web API - 将 Dynamics CRM 的权限配置为具有“以组织用户身份访问 CRM Online”的委派权限 - 并创建了一个有效期为 1 年的密钥并保持生成的客户 ID。 在 Azure 上配置 Web 应用程序后,我在 .NET/C# 中创建了一个控制台应用程序,它使用 ADAL 发出一个简单的请求,在本例中是检索帐户列表:

    class Program

    private static string ApiBaseUrl = "https://xxxxx.api.crm4.dynamics.com/";
    private static string ApiUrl = "https://xxxxx.api.crm4.dynamics.com/api/data/v8.1/";
    private static string ClientId = "2a5dcdaf-2036-4391-a3e5-9d0852ffe3f2";
    private static string AppKey = "symCaAYpYqhiMK2Gh+E1LUlfxbMy5X1sJ0/ugzM+ur0=";

    static void Main(string[] args)
    
        AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(ApiUrl)).Result;

        var clientCredential = new ClientCredential(ClientId, AppKey);

        var authenticationContext = new AuthenticationContext(ap.Authority);
        var authenticationResult = authenticationContext.AcquireToken(ApiBaseUrl, clientCredential);

        var httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);

        var result = httpClient.GetAsync(Path.Combine(ApiUrl, "accounts")).Result;         
    

我成功检索了访问令牌,但是当我尝试向 CRM 发出 httprequest 时,我总是收到 401 - 未授权状态代码。我错过了什么?

【问题讨论】:

我相信它对令牌的权限不正确。您正在做的是使用应用程序凭据来获取包含。您在添加 CRM 时选择的权限是 Delegated PErmissions。两者都是不同的东西。如果使用同一目录下用户的 User Creds 进行身份验证和访问会怎样? 我之前创建了一个本地客户端应用程序,并成功地与 CRM 集成,但我必须提供用户凭据才能从 Azure 获取令牌。我的目标是完全避免使用用户凭据。为此,我试图通过密钥交换(我在帖子中解释的方法)或通过证书获取令牌。 你检查了吗? msdn.microsoft.com/en-us/library/gg327838.aspx 是的。但是该教程仅适用于创建本机客户端应用程序,您始终必须为此提供用户凭据才能检索令牌。我正在尝试使用密钥或证书身份验证来获取令牌,就像 site 在 3 和 7 中解释的那样: 你有什么发现吗? 【参考方案1】:

感谢大家的回答。我终于设法使用 ADAL 3 访问 Dynamics CRM OData API。

由于许多人在执行此操作时仍然遇到问题,请参阅以下步骤:

应用注册

    使用您的 Dynamics CRM 订阅的 Office 365 管理员用户登录 portal.azure.com

    转到 Azure Active Director\App 注册并添加新的应用程序注册

    输入“姓名”和“登录网址”,网址可以是任何内容(例如https://localhost)

    选择刚刚创建的注册应用,进入Settings\Keys

    输入密钥描述,单击保存并复制值(并保留它,因为您以后需要它)。同时复制已注册应用的应用程序 ID。

    转到“必需权限”,单击“添加”,选择“Dynamics CRM Online”,然后勾选“以组织用户身份访问 CRM Online”。

这些步骤使客户端应用程序能够使用您在第 5 步中创建的应用程序 ID 和客户端密码访问 Dynamics CRM。 您的客户端应用程序现在可以针对 Azure AD 进行身份验证,并获得访问 CRM Online 的权限。但是,CRM Online 不知道这个“客户端应用程序”或“用户”。如果您尝试访问 CRM API,它将响应 401。

添加 CRM 应用用户

要让 CRM 了解“客户端应用程序”或“用户”,您需要添加应用程序用户。

    转到 CRM\Security Roles,创建一个新的安全角色或复制“系统管理员”角色

    转到 CRM\Settings\Security\Users,创建一个新用户,将表单更改为“应用程序用户”

    使用您在上一步中拥有的应用程序 ID 输入必填字段。保存后,CRM 将自动填充 Azure AD 对象 ID 和 URI。

    将用户添加到上一步创建的安全角色。

现在您应该能够使用 HttpClient 和 ADAL 使用以下示例代码访问 CRM API:

var ap = await AuthenticationParameters.CreateFromResourceUrlAsync(
                new Uri("https://*****.api.crm6.dynamics.com/api/data/v9.0/"));

String authorityUrl = ap.Authority;
String resourceUrl = ap.Resource;

var authContext = new AuthenticationContext(authorityUrl);
var clientCred = new ClientCredential("Application ID", "Client Secret");
var test = await authContext.AcquireTokenAsync(resourceUrl, clientCred);

Console.WriteLine(test.AccessToken);

using (var client = new HttpClient())

    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", test.AccessToken);

    var response = await client.GetAsync("https://*****.api.crm6.dynamics.com/api/data/v9.0/contacts");
    var contacts = await response.Content.ReadAsStringAsync();

    Console.WriteLine(contacts);

【讨论】:

非常有帮助,您的评论立即解决了我的问题。感谢 Stefan 让我摆脱这种陈规。 如何在java中使用Application Id?【参考方案2】:

1 年零 2 个月后,同样的代码完美运行。正如许多人所说,Dynamics 365 同时开始支持服务器到服务器 (S2S) 身份验证。我必须做的唯一一个我当时没有做的步骤是创建一个应用程序用户。 有关如何进行此身份验证的更多信息,请查看此网站:https://msdn.microsoft.com/en-us/library/mt790170.aspx

【讨论】:

您能否分享一些有关您如何使其工作的更多细节?我在同一条船上并尝试使用 client_credentials 授权类型来访问 d365 web api?【参考方案3】:

我建议您查看服务器到服务器 (S2S) 身份验证,该身份验证已在最新版本中添加到 Dynamics 365。

通过使用 S2S,您不需要付费的 Dynamics 365 许可证。不是用户凭据,而是基于存储在 Dynamics 365 应用程序用户记录中的 Azure AD 对象 ID 值标识的服务主体对应用程序进行身份验证。

更多信息可以在这里找到: https://msdn.microsoft.com/en-us/library/mt790168.aspx https://msdn.microsoft.com/en-us/library/mt790170.aspx

【讨论】:

【参考方案4】:

您的 ClientId,来自 Azure 的 AppKey,所以 ap.Authority 应该是 https://login.microsoftonline.com/tenantid in var authenticationContext = new AuthenticationContext(ap.Authority);

【讨论】:

我尝试使用您建议的 URL,但仍然未获得授权。生成的请求消息是这个,其中令牌被 TOKEN 替换:Method: GET, RequestUri: 'xxxxx.api.crm4.dynamics.com/api/data/v8.1/accounts', Version: 1.1, Content: , Headers: Authorization: Bearer TOKEN 跨度> 您是否尝试下载Manifest并打开JSON文件并找到行:“oauth2AllowImplicitFlow”:false,并将false更改为true并上传文件。【参考方案5】:

我认为您无法绕过向至少某种“集成帐户”提供用户凭据。您可以通过以下方式避免更传统的弹出/重定向 OAUTH 流程:

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.IO;
using System.Net;

namespace ConsoleApplication2

    class Program
    
        private static string API_BASE_URL = "https://<CRM DOMAIN>/";
        private static string API_URL = "https://<CRM DOMAIN>/api/data/v8.1/";
        private static string CLIENT_ID = "<CLIENT ID>";

        static void Main(string[] args)
        
            var userCredential = new UserCredential("<USERNAME>", "<PASSWORD>");
            var authContext = new AuthenticationContext("https://login.windows.net/common", false);
            var result = authContext.AcquireToken(API_BASE_URL, CLIENT_ID, userCredential);

            var httpClient = HttpWebRequest.CreateHttp(Path.Combine(API_URL, "accounts"));
            httpClient.Headers.Add(HttpRequestHeader.Authorization, "Bearer:" + result.AccessToken);
            using (var sr = new StreamReader(httpClient.GetResponse().GetResponseStream()))
            
                Console.WriteLine(sr.ReadToEnd());
            

            Console.ReadLine();
        
    

注意:我使用的是旧版本的 ADAL (2.19.208020213),因为看起来 password 参数已从 UserCredential 构造函数中取出。

编辑: CRM 现在支持Server to Server Authentication,它允许您创建应用程序用户。

【讨论】:

【参考方案6】:

您可能需要在 CRM 中设置应用程序用户以与您的 Azure 应用程序匹配: https://msdn.microsoft.com/en-us/library/mt790170.aspx

虽然您可以在 C# 中设置不记名令牌,但由于 CRM 级别权限,对 CRM 资源的 Web 请求可能会失败。

【讨论】:

我确实设置了一个具有相同应用程序 ID 和适当安全角色的应用程序用户。我可以使用 oauth 客户端凭据授予创建不记名令牌,但是当我尝试使用它时,我得到 401 未授权。完全不确定我做错了什么。

以上是关于401- 使用 REST API Dynamics CRM 和 Azure AD 进行未经授权的身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Dynamics CRM 2016 Online Rest API 与客户端凭据 OAuth 流

Xampp + Wordpress Rest API(401 代码:rest_cannot_create)

Cosmos db Rest API - 错误 401 未经授权

访问 PayPal 沙箱 Rest API 时响应 401

Thingsboard REST api 始终以状态 401 响应

paypal rest api支付调用使用php返回401