Condividi tramite


Codice helper API Web: classe di autenticazione

 

Data di pubblicazione: gennaio 2017

Si applica a: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Utilizza la classe Authentication per stabilire facilmente una connessione convalidata a un servizio Web Microsoft Dynamics 365. Questa classe supporta due protocolli di autenticazione: Autenticazione di Windows per Dynamics 365 locale o OAuth 2.0 per Dynamics 365 (online) o distribuzioni con connessione Internet (IFD). Questa classe utilizza la libreria di autenticazione di Microsoft Azure Active Directory (ADAL) per gestire il protocollo OAuth.

La classe Authentication si trova nel file Authentication.cs nella Libreria helper API Web CRM SDK È progettato per essere usato insieme alla gerarchia di classi helper Configuration per consentirti di stabilire una connessione sicura al servizio Dynamics 365 tramite un oggetto di tipo System.Net.Http.HttpMessageHandler. Per ulteriori informazioni, vedere Utilizzare la libreria helper API Web di Microsoft Dynamics 365 (C#).

Processo di autenticazione

Il meccanismo usato dalla classe Authentication per l'autenticazione con un servizio Dynamics 365 dipende dalle informazioni passate al costruttore con il parametro Configuration. Tenta di creare un oggetto derivato da HttpMessageHandler che puoi utilizzare per creare un'istanza di System.Net.Http perHttpClient e fornire una sessione di comunicazione sicura e persistente con il servizio Dynamics 365.

Innanzitutto viene eseguita una breve ricerca con il servizio Dynamics 365 specificato per determinare se è in uso l'autenticazione nativa di Windows o OAuth.

  • Se è usato OAuth, viene creato un oggetto OAuthMessageHandler tramite l'autorità di autenticazione individuata nella ricerca. Questa classe, derivata da System.Net.Http.DelegatingHandler, aggiorna il token di accesso OAuth a ogni richiesta, pertanto non è necessario gestire in modo esplicito la scadenza del token.

  • Se viene usata l'autenticazione di Windows e vengono fornite le credenziali dell'utente, tali credenziali vengono utilizzate per creare un HttpClientHandler.

  • Se viene usata l'autenticazione di Windows me le credenziali dell'utente non vengono fornite, HttpClientHandler viene costruito usando le credenziali di rete predefinite.

Gerarchia delle classi e membri

Nella tabella seguente vengono elencati i membri pubblici della classe Authentication.

Libreria helper API Web Dynamics 365 - Diagramma classe di autenticazione

Classe di autenticazione

Proprietà:

Authority - l'URL del server che gestisce l'autenticazione OAuth.

ClientHandler - l'oggetto derivato da HttpMessageHandler che fornisce le credenziali di rete o il token di accesso di autorizzazione per le richieste di messaggio.

Context - l'oggetto AuthenticationContext per un evento di autenticazione.


Metodi:

AquireToken - per OAuth, restituisce un oggetto AuthenticationResult contenente i token di accesso e di aggiornamento, per il contesto di autenticazione corrente.

Authentication - inizializza un'istanza di questa classe usando il parametro Configuration.

DiscoverAuthority - Scopre l'autorità di autenticazione del servizio Web Dynamics 365.


Classe OAuthMessageHandler

Questa classe annidata imposta l'intestazione di autorizzazione per ogni messaggio inviato per le distribuzioni IFD e Dynamics 365 (online).

Uso

Le classi Configuration e Authentication sono progettate per essere utilizzate insieme per stabilire una connessione sicura al servizio Dynamics 365 di destinazione. Innanzitutto crea un oggetto di tipo Configuration, quindi passalo come singolo parametro al costruttore Authentication. Dopo la conclusione della creazione, puoi usare la proprietà ClientHandler per creare una connessione client HTTP sicura, autenticata e persistente al servizio Dynamics 365.

Una modalità comune per eseguire questa operazione, utilizzata nella maggior parte degli esempi C# API Web, consiste nell'uso della classe derivata FileConfiguration per leggere le informazioni di connessione dai file di configurazione dell'applicazione debitamente creati, come stato illustrato di seguito.

FileConfiguration config = new FileConfiguration(null);
Authentication auth = new Authentication(config);
httpClient = new HttpClient(auth.ClientHandler, true);

Per ulteriori informazioni su questa modalità, vedi la sezione ere la sezione Impostazioni di connessione FileConfiguration. Sebbene la classe Authentication contenga diversi altri metodi e proprietà pubbliche, sono principalmente forniti a supporto della creazione della proprietà ClientHandler e raramente la maggior parte delle applicazioni client vi eseguono direttamente l'accesso.

Elenco delle classi

L'origine più aggiornata per la classe è disponibile nella Libreria helper API Web CRM SDK nel pacchetto di NuGet.

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading.Tasks;

namespace Microsoft.Crm.Sdk.Samples.HelperCode
{
    /// <summary>
    /// Manages user authentication with the Dynamics CRM Web API (OData v4) services. This class uses Microsoft Azure
    /// Active Directory Authentication Library (ADAL) to handle the OAuth 2.0 protocol. 
    /// </summary>
    public class Authentication
    {
        private Configuration _config = null;
        private HttpMessageHandler _clientHandler = null;
        private AuthenticationContext _context = null;
        private string _authority = null;

        #region Constructors
        /// <summary>
        /// Base constructor.
        /// </summary>
        public Authentication() { }

        /// <summary>
        /// Establishes an authentication session for the service.
        /// </summary>
        /// <param name="config">A populated configuration object.</param>
        public Authentication(Configuration config)
            : base()
        {
            if (config == null)
                throw new Exception("Configuration cannot be null.");

            _config = config;

            SetClientHandler();
        }

        /// <summary>
        /// Custom constructor that allows adding an authority determined asynchronously before 
        /// instantiating the Authentication class.
        /// </summary>
        /// <remarks>For a WPF application, first call DiscoverAuthorityAsync(), and then call this
        /// constructor passing in the authority value.</remarks>
        /// <param name="config">A populated configuration object.</param>
        /// <param name="authority">The URL of the authority.</param>
        public Authentication(Configuration config, string authority)
            : base()
        {
            if (config == null)
                throw new Exception("Configuration cannot be null.");

            _config = config;
            Authority = authority;

            SetClientHandler();
        }
        #endregion Constructors

        #region Properties
        /// <summary>
        /// The authentication context.
        /// </summary>
        public AuthenticationContext Context
        {
            get
            { return _context; }

            set
            { _context = value; }
        }

        /// <summary>
        /// The HTTP client message handler.
        /// </summary>
        public HttpMessageHandler ClientHandler
        {
            get
            { return _clientHandler; }

            set
            { _clientHandler = value; }
        }


        /// <summary>
        /// The URL of the authority to be used for authentication.
        /// </summary>
        public string Authority
        {
            get
            {
                if (_authority == null)
                    _authority = DiscoverAuthority(_config.ServiceUrl);

                return _authority;
            }

            set { _authority = value; }
        }
        #endregion Properties

        #region Methods
        /// <summary>
        /// Returns the authentication result for the configured authentication context.
        /// </summary>
        /// <returns>The refreshed access token.</returns>
        /// <remarks>Refresh the access token before every service call to avoid having to manage token expiration.</remarks>
        public AuthenticationResult AcquireToken()
        {
            if (_config != null && (!string.IsNullOrEmpty(_config.Username) && _config.Password != null))
            {
                UserCredential cred = new UserCredential(_config.Username, _config.Password);
                return _context.AcquireToken(_config.ServiceUrl, _config.ClientId, cred);
            }
            return _context.AcquireToken(_config.ServiceUrl, _config.ClientId, new Uri(_config.RedirectUrl),
                PromptBehavior.Auto);
        }

        /// <summary>
        /// Returns the authentication result for the configured authentication context.
        /// </summary>
        /// <param name="username">The username of a CRM system user in the target organization. </param>
        /// <param name="password">The password of a CRM system user in the target organization.</param>
        /// <returns>The authentication result.</returns>
        /// <remarks>Setting the username or password parameters to null results in the user being prompted to
        /// enter log-on credentials. Refresh the access token before every service call to avoid having to manage
        /// token expiration.</remarks>
        public AuthenticationResult AcquireToken(string username, SecureString password)
        {

            try
            {
                if (!string.IsNullOrEmpty(username) && password != null)
                {
                    UserCredential cred = new UserCredential(username, password);
                    return _context.AcquireToken(_config.ServiceUrl, _config.ClientId, cred);
                }
            }
            catch (Exception e)
            {
                throw new Exception("Authentication failed. Verify the configuration values are correct.", e);
            }
            return null;
        }


        /// <summary>
        /// Discover the authentication authority.
        /// </summary>
        /// <returns>The URL of the authentication authority on the specified endpoint address, or an empty string
        /// if the authority cannot be discovered.</returns>
         public static string DiscoverAuthority(string serviceUrl)
        {
            try
            {
                AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(
                    new Uri(serviceUrl + "api/data/")).Result;

                return ap.Authority;
            }
            catch (HttpRequestException e)
            {
                throw new Exception("An HTTP request exception occurred during authority discovery.", e);
            }
            catch (System.Exception e )
            {
                // This exception ocurrs when the service is not configured for OAuth.
                if( e.HResult == -2146233088 )
                {
                    return String.Empty;
                }
                else
                {
                    throw e;
                }
            }
        }

        /// <summary>
        /// Discover the authentication authority asynchronously.
        /// </summary>
        /// <param name="serviceUrl">The specified endpoint address</param>
        /// <returns>The URL of the authentication authority on the specified endpoint address, or an empty string
        /// if the authority cannot be discovered.</returns>
        public static async Task<string> DiscoverAuthorityAsync(string serviceUrl)
        {
            try
            {
                AuthenticationParameters ap = await AuthenticationParameters.CreateFromResourceUrlAsync(
                    new Uri(serviceUrl + "api/data/"));

                return ap.Authority;
            }
            catch (HttpRequestException e)
            {
                throw new Exception("An HTTP request exception occurred during authority discovery.", e);
            }
            catch (Exception e)
            {
                // These exceptions ocurr when the service is not configured for OAuth.

                // -2147024809 message: Invalid authenticate header format Parameter name: authenticateHeader
                if (e.HResult == -2146233088 || e.HResult == -2147024809)
                {
                    return String.Empty;
                }
                else
                {
                    throw e;
                }
            }
        }

        /// <summary>
        /// Sets the client message handler as appropriate for the type of authentication
        /// in use on the web service endpoint.
        /// </summary>
        private void SetClientHandler()
        {
            // Check the Authority to determine if OAuth authentication is used.
            if (String.IsNullOrEmpty(Authority))
            {
                if (_config.Username != String.Empty)
                {
                    _clientHandler = new HttpClientHandler()
                    { Credentials = new NetworkCredential(_config.Username, _config.Password, _config.Domain) };
                }
                else
                // No username is provided, so try to use the default domain credentials.
                {
                    _clientHandler = new HttpClientHandler()
                    { UseDefaultCredentials = true };
                }
            }
            else
            {
                _clientHandler = new OAuthMessageHandler(this, new HttpClientHandler());
                _context = new AuthenticationContext(Authority, false);
            }
        }
        #endregion Methods

        /// <summary>
        /// Custom HTTP client handler that adds the Authorization header to message requests. This
        /// is required for IFD and Online deployments.
        /// </summary>
        class OAuthMessageHandler : DelegatingHandler
        {
            Authentication _auth = null;

            public OAuthMessageHandler( Authentication auth, HttpMessageHandler innerHandler )
                : base(innerHandler)
            {
                _auth = auth;
            }

            protected override Task<HttpResponseMessage> SendAsync(
                HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
            {
                // It is a best practice to refresh the access token before every message request is sent. Doing so
                // avoids having to check the expiration date/time of the token. This operation is quick.
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _auth.AcquireToken().AccessToken);

                return base.SendAsync(request, cancellationToken);
            }
        }
    }
}

Vedere anche

Informazioni generali sull'API Web Microsoft Dynamics 365 (C#)
Avviare un progetto API Web di Dynamics 365 in Visual Studio (C#)
Utilizzare la libreria helper API Web di Microsoft Dynamics 365 (C#)
Codice helper API Web: classi di configurazione
Codice helper API Web: CrmHttpResponseException class

Microsoft Dynamics 365

© 2017 Microsoft. Tutti i diritti sono riservati. Copyright