简体   繁体   English

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

[英]401- Unauthorized authentication using REST API Dynamics CRM with Azure AD

I'm trying to access a Dynamics CRM Online REST API with Azure AD oAuth 2 Authentication. 我正在尝试使用Azure AD oAuth 2身份验证访问Dynamics CRM Online REST API。 In order to do so I followed these steps: 为此,我按照以下步骤操作:

- I've registered a web application and/or web api in Azure - 我在Azure中注册了一个Web应用程序和/或web api
- Configured the permissions to Dynamics CRM to have Delegated permissions "Access CRM Online as organization user" - 将动态CRM的权限配置为具有委派权限“以组织用户身份访问CRM Online”
- And created a Key with a 1 year expiration and kept the Client ID generated. - 并创建了一个有效期为1年的密钥并保留了客户端ID。

After the web app was configured on Azure I have created a Console application in .NET/C# that uses ADAL to make a simple request, in this case to retrieve a list of accounts: 在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;         
    }
}

I retrieve an access token successfully but when I try to do a httprequest to CRM I always get a 401 - Unauthorized status code . 我成功检索了一个访问令牌,但是当我尝试对CRM进行httprequest时,我总是得到一个401 - 未经授权的状态代码 What am I missing? 我错过了什么?

Thanks everyone for your answers. 谢谢大家的回答。 I finally managed to access Dynamics CRM OData API using ADAL 3. 我终于使用ADAL 3访问了Dynamics CRM OData API。

Since many people are still having problems doing this, see the following steps: 由于许多人在执行此操作时仍遇到问题,请参阅以下步骤:

App registration 应用注册

  1. Log into portal.azure.com using your Office 365 administrator user of your Dynamics CRM subscription. 使用Dynamics CRM订阅的Office 365管理员用户登录portal.azure.com

  2. Go to Azure Active Director\\App registrations and add New application registrations 转到Azure Active Director \\ App注册并添加新的应用程序注册

  3. Enter "Name" and "Sign-on URL", the URL could be anything ( https://localhost for example) 输入“名称”和“登录URL”,URL可以是任何内容(例如https:// localhost

  4. Select the registered app you just created, go to Settings\\Keys 选择刚刚创建的注册应用程序,转到Settings \\ Keys

  5. Enter a key description, click Save and copy the Value (and keep it since you will need it later). 输入密钥描述,单击“保存”并复制“值”(并保留它,因为稍后您将需要它)。 Also copy the Application ID of the registered app. 同时复制已注册应用程序的应用程序ID。

  6. Go to "Required Permissions", click Add, select "Dynamics CRM Online" then tick "Access CRM Online as organisation users". 转到“必需权限”,单击“添加”,选择“Dynamics CRM Online”,然后选中“以组织用户身份访问CRM Online”。

These steps enable a client application to access Dynamics CRM by using the Application ID and the client secret you created in step 5. Your client application is now able to be authenticated against Azure AD with permission to access CRM Online. 这些步骤使客户端应用程序可以使用您在步骤5中创建的应用程序ID和客户端密钥来访问Dynamics CRM。您的客户端应用程序现在可以通过访问CRM Online的权限对Azure AD进行身份验证 However, CRM Online does not know about this "client application" or "user". 但是,CRM Online不了解这个“客户端应用程序”或“用户”。 CRM API will response a 401 if you try to access it. 如果您尝试访问它,CRM API将响应401。

Add CRM application user 添加CRM应用程序用户

To let CRM know about the "client application" or "user", you'll need to add an application user. 要让CRM了解“客户端应用程序”或“用户”,您需要添加应用程序用户。

  1. Go to CRM\\Security Roles, create a new Security Role or just copy the "System Administrator" Role 转到CRM \\安全角色,创建新的安全角色或只复制“系统管理员”角色

  2. Go to CRM\\Settings\\Security\\Users, create a new User, change the form to "Application User" 转到CRM \\ Settings \\ Security \\ Users,创建一个新用户,将表单更改为“Application User”

  3. Enter the required fields with the Application ID that you have in previous step. 使用上一步中的应用程序ID输入必填字段。 Once saved, CRM will auto populate the Azure AD Object ID and the URI. 保存后,CRM将自动填充Azure AD对象ID和URI。

  4. Add the user to the Security Role created from previous step. 将用户添加到从上一步创建的安全角色。

Now you should be able to access CRM API using HttpClient and ADAL using the sample code below: 现在,您应该能够使用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);
}

1 year and 2 months later, this same code works perfectly . 1年零2个月后, 这段相同的代码完美无缺 As many have stated, Dynamics 365 started to support Server-to-Server (S2S) authentication in the meantime. 正如许多人所说,Dynamics 365在此期间开始支持服务器到服务器(S2S)身份验证。 The only step that I had to make that I didn't back then was to create an application user. 我不得不做的唯一一步就是创建一个应用程序用户。 For more information about how to make this authentication work check this website: https://msdn.microsoft.com/en-us/library/mt790170.aspx 有关如何进行此身份验证的详细信息,请访问以下网站: https//msdn.microsoft.com/en-us/library/mt790170.aspx

I'd advise you to have a look at Server-to-Server (S2S) authentication, which was added to Dynamics 365 in the latest release. 我建议您查看服务器到服务器(S2S)身份验证,该身份验证已在最新版本中添加到Dynamics 365中。

By using S2S you do not need a paid Dynamics 365 license. 通过使用S2S,您不需要付费的Dynamics 365许可证。 Rather than user credentials, the application is authenticated based on a service principal identified by an Azure AD Object ID value which is stored in the Dynamics 365 application user record. 不是用户凭据,而是基于由Azure AD对象ID值标识的服务主体对应用程序进行身份验证,该值存储在Dynamics 365应用程序用户记录中。

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

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

I don't think you'll be able to get around providing user credentials to at least some kind of "integration account". 我不认为你能够至少为某种“集成帐户”提供用户凭据。 You can avoid a more traditional popup/redirect OAUTH flow with the following: 您可以使用以下内容避免更传统的弹出/重定向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();
        }
    }
}

Note: I'm using an older version of ADAL ( 2.19.208020213 ) as it appears the password parameter has been taken out of the UserCredential constructor. 注意:我使用的是旧版本的ADAL( 2.19.208020213 ),因为看起来password参数已从UserCredential构造函数中取出。

EDIT: CRM now supports Server to Server Authentication which allows you to create an application user. 编辑: CRM现在支持服务器到服务器身份验证 ,允许您创建应用程序用户。

You may need an Application User set-up inside CRM to match with your Azure Application: https://msdn.microsoft.com/en-us/library/mt790170.aspx 您可能需要在CRM中设置应用程序用户以与您的Azure应用程序匹配: https//msdn.microsoft.com/en-us/library/mt790170.aspx

Whilst you can get your Bearer Token setup in C#, the web request to the CRM resource may fail due to CRM level permissions. 虽然您可以在C#中设置Bearer Token,但由于CRM级别权限,对CRM资源的Web请求可能会失败。

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

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