简体   繁体   中英

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

I have a web application that needs to speak with Dynamics CRM 365 Web API. The Dynamics CRM is configured as a Relying Party on ADFS. The server is Windows Server 2016 and everything is on premise and not on Azure.

What I did to acquire a valid token are the following:

1) In ADFS went to Application Groups and add an new Server Application, took the ClientID and also generate a Client Secret for my web application.

在此处输入图片说明

2) Add new new user in Active Directory the webAppUser

3) Add this user as an Application User in CRM with Application ID the ClientID I got earlier when I registered my web app to ADFS. Also created a new Role with full permissions on Entity Account and assign this role to this Application User

4) I'm using the below code to retrieve a bearer token and add it to my HttpClient Authorization 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) I manage to get a token but when I call the CRM's Web Api I still get 401 Unauthorized.

At the end i had to use a system user and send it's credentials in my oAUth request using the code below in order to acquire a valid token:

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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