授权 WebApp 到 ADFS 以访问 Dynamics CRM Web API

Authorize WebApp to ADFS in order to access Dynamics CRM Web API

我有一个 Web 应用程序需要与 Dynamics CRM 365 Web API 通信。 Dynamics CRM 配置为 ADFS 上的依赖方。 服务器是 Windows Server 2016,一切都在本地而不是在 Azure 上。

我为获得有效令牌所做的工作如下:

1) 在 ADFS 中转到应用程序组并添加一个新的服务器应用程序,获取 ClientID 并为我的 Web 应用程序生成一个客户端密码。

2) 在 Active Directory 中添加新用户 webAppUser

3) 将此用户添加为 CRM 中的应用程序用户,其应用程序 ID 是我之前在将 Web 应用程序注册到 ADFS 时获得的 ClientID。还创建了一个对实体帐户具有完全权限的新角色,并将此角色分配给此应用程序用户

4) 我正在使用以下代码检索不记名令牌并将其添加到我的 HttpClient 授权 header.

public class CrmWebApiClient
{
    private HttpClient _httpClient;

    public CrmWebApiClient()
    {
        _httpClient = new HttpClient();
        _httpClient.BaseAddress = new Uri("https://crmbaseaddress.com");            
    }

    internal async Task Initialize()
    {
        try
        {               
            var authority = "https://adfsServerUrl/adfs/";
            var authContext = new AuthenticationContext(authority,false);
            var credentials = new ClientCredential(clientID,clientSecret);

            var authResult = await authContext.AcquireTokenAsync("https://crmbaseaddress.com", credentials);

            _httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
        }
        catch (Exception ex)
        {
            var error = ex;
        }

    }

    internal async Task<string> GetValuesAsync()
    {
        var result = string.Empty;
        try
        {
            result = await _httpClient.GetStringAsync("api/data/v8.1/accounts");
        }
        catch (Exception ex)
        {
            var error = ex;
        }

        return result;
    }
}

5) 我设法获得了令牌,但是当我调用 CRM 的 Web 时 Api 我仍然收到 401 Unauthorized。

最后我不得不使用系统用户并使用下面的代码在我的 oAUth 请求中发送它的凭据以获得有效令牌:

namespace TestApp.App_Start {
public class CrmWebApiClient
{
    private HttpClient _httpClient;

    public CrmWebApiClient()
    {       
        _httpClient = new HttpClient();
        _httpClient.BaseAddress = new Uri("https://crmUrl");
        _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        _httpClient.DefaultRequestHeaders.Add("OData-MaxVersion","4.0");
        _httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
    }

    internal async Task Initilize()
    {
        try
        {

            var tokenClient = new HttpClient();             
            var content = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string,string>("client_id",_clientID),
                new KeyValuePair<string,string>("client_secret",_clientSecret),
                new KeyValuePair<string,string>("resource",_urlOfResource),
                new KeyValuePair<string,string>("username",_usernameOfSystemUser),
                new KeyValuePair<string,string>("password",_passwordOfSystemUser),
                new KeyValuePair<string,string>("grant_type","password"),
            });
            var res = tokenClient.PostAsync("https://adfsUrl/adfs/oauth2/token", content);
            var respo = res.Result.Content.ReadAsStringAsync().Result;
            var accesstoken = JObject.Parse(respo).GetValue("access_token").ToString();

            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesstoken);

        }
        catch (Exception ex)
        {
            Trace.WriteLine($"Exception when requesting the bearer token from ADFS: {ex.Message} - {ex.InnerException?.Message}");
        }

    }

    internal async Task<string> GetAccountsAsync()
    {
        var result = string.Empty;
        try
        {
            result = _httpClient.GetStringAsync("/api/data/v8.0/accounts").Result;

        }
        catch (Exception ex)
        {
            Trace.WriteLine($"Exception when calling the CRM api: {ex.Message} - {ex.InnerException?.Message}");
        }
        return result;
    }
}
}


// Use the above class like that
var httpClient = new CrmWebApiClient();
httpClient.Initilize().Wait();
var result = httpClient.GetAccountsAsync().Result;