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

401-使用REST API Dynamics CRM和Azure AD进行未经授权的身份验证,rest,azure,oauth-2.0,dynamics-crm,adal,Rest,Azure,Oauth 2.0,Dynamics Crm,Adal,我正在尝试使用Azure AD oAuth 2身份验证访问Dynamics CRM Online REST API。为此,我遵循以下步骤: -我已在Azure中注册了web应用程序和/或web api -将Dynamics CRM的权限配置为具有“以组织用户身份访问CRM Online”的委派权限 -并创建了一个过期1年的密钥,并保留生成的客户端ID。 在Azure上配置web应用程序后,我在.NET/C#中创建了一个控制台应用程序,该应用程序使用ADAL发出简单请求,在本例中检索帐户列表:

我正在尝试使用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-未经授权状态代码。我遗漏了什么?

你的客户ID,Azure的AppKey,所以
ap.权限应该是
https://login.microsoftonline.com/tenantid
in
var authenticationContext=新的authenticationContext(ap.Authority)

我认为您至少无法绕开向某种“集成帐户”提供用户凭据。您可以通过以下方式避免更传统的弹出/重定向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();
        }
    }
}
使用Microsoft.IdentityModel.Clients.ActiveDirectory;
使用制度;
使用System.IO;
Net系统;
命名空间控制台应用程序2
{
班级计划
{
私有静态字符串API_BASE_URL=“https://”;
私有静态字符串API_URL=”https:///api/data/v8.1/";
私有静态字符串客户端_ID=“”;
静态void Main(字符串[]参数)
{
var userCredential=newusercredential(“,”);
var authContext=新的AuthenticationContext(“https://login.windows.net/common“,假);
var result=authContext.AcquireToken(API\u BASE\u URL、客户端\u ID、用户凭证);
var httpClient=HttpWebRequest.CreateHttp(Path.Combine(API_URL,“accounts”);
httpClient.Headers.Add(HttpRequestHeader.Authorization,“承载者:“+result.AccessToken”);
使用(var sr=newstreamreader(httpClient.GetResponse().GetResponseStream())
{
Console.WriteLine(sr.ReadToEnd());
}
Console.ReadLine();
}
}
}
注意:我使用的是旧版本的ADAL(),因为
password
参数似乎已从
UserCredential
构造函数中取出


编辑:CRM现在支持创建应用程序用户。

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

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

更多信息可在此处找到:
一年零两个月后,同样的代码可以完美地工作。正如许多人所说,Dynamics 365同时开始支持服务器到服务器(S2S)身份验证。我当时唯一没有做的一步就是创建一个应用程序用户。
有关如何使此身份验证生效的更多信息,请查看此网站:

您可能需要在CRM中设置应用程序用户以与Azure应用程序相匹配:


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

谢谢大家的回答。我最终使用ADAL3访问了DynamicsCRM ODataAPI

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

应用程序注册
  • 使用Dynamics CRM订阅的Office 365管理员用户登录
    portal.azure.com

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

  • 输入“名称”和“登录URL”,URL可以是任何内容(例如)

  • 选择您刚刚创建的注册应用,转到设置\按键

  • 输入密钥描述,单击“保存”并复制该值(并保留该值,因为以后需要它)。同时复制已注册应用程序的应用程序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(
    新的Uri(“https://*****api.crm6.dynamics.com/api/data/v9.0/”);
    字符串authorityUrl=ap.Authority;
    字符串resourceUrl=ap.Resource;
    var authContext=新的AuthenticationContext(authorityUrl);
    var clientCred=new ClientCredential(“应用程序ID”)