Internet-API-Hilfecode: Authentifizierungsklasse

 

Veröffentlicht: Januar 2017

Gilt für: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Verwenden Sie die Authentication-Klasse, die im überprüften Einrichten einer Verbindung mit einem Webdienst Microsoft Dynamics 365 unterstützt. Diese Klasse unterstützt zwei Authentifizierungsprotokolle: Windows-Authentifizierung Dynamics 365 für lokal bzw. OAuth 2,0 für Dynamics 365 (Online) oder Bereitstellungen mit Internetzugriff (IFDs). Diese Klasse basiert auf der Authentifizierungs-Bibliothek Microsoft Azure Active Directory (ADAL), um OAuth-Protokolle zu bearbeiten.

Die Authentication-Klasse ist neu in der Authentication.cs Datei in der CRM-SDK Web API Hilfe-Bibliothek Er wurde entworfen, um in Verbindung mit der Configuration Hilfsklassenhierarchie zu arbeiten, damit Sie eine sichere Verbindung mit Ihrem Dynamics 365-Service über ein Objekt vom Typ System.Net.Http einrichten.HttpMessageHandler Weitere Informationen finden Sie unter Verwenden Sie die Microsoft Dynamics 365 WEB API Hilfe-Bibliothek (C#).

Authentifizierungsprozess

Die Funktion, die die Authentication-Klasse verwendet, um einen Dynamics 365-Service zu authentifizieren, hängt von den Informationen ab, die Sie dem Konstruktor mit dem Configuration-Parameter weitergeben. Es versucht, ein HttpMessageHandler-abgeleitetes Objekt zu erstellen, das Sie verwenden können, um eine System.Net. HttpClient-Instanz zu instantiieren, um sichere, dauerhafte Kommunikationssitzungen mit dem Dynamics 365-Service bereitzustellen.

Zuerst wird ein kurzer Discoveryhandshake mit dem angegebenen Dynamics 365-Service ausgeführt, um zu bestimmen, ob OAuths oder die Windows systemeigene Authentifizierung verwendet wird.

  • Wenn OAuth verwendet wird, wird ein OAuthMessageHandler-Objekt mit der Authentifizierungsbehörde erstellt, die im Handshake ermittelt wurde. Diese Klasse, die von System.Net.Http.DelegatingHandler abgeleitet wird, aktualisiert den OAuth-Zugangstoken bei jeder Anforderung, sodass Sie den Tokenablauf nicht explizit verwalten müssen.

  • Wenn Windows-Authentifizierung verwendet und die Benutzeranmeldeinformationen angegeben werden, werden anschließend jene Anmeldeinformationen verwendet, um einen HttpClientHandler zu erstellen

  • Wenn Windows-Authentifizierung verwendet wird, aber die Benutzeranmeldeinformationen nicht bereitgestellt wird, wird ein HttpClientHandler mit den standardmäßigen Netzwerkanmeldeinformationen erstellt.

Klassenhierarchie und -mitglieder

Die folgende Tabelle gibt Aufschluss über öffentliche Mitglieder der Authentication-Klasse.

Dynamics 365-Internet API Hilfe-Bibliothek-Authentifizierungs-Klassendiagramm

Authentifizierungsklasse

Eigenschaften:

Authority – Die URL des Servers, die die OAuth-Authentifizierung verwaltet.

ClientHandler – Der HttpMessageHandler, der vom Objekt abgeleitet ist, der die Netzwerkanmeldeinformationen oder den Autorisierungszugriffstoken für Nachrichtenanforderungen bereitstellt.

Context –, die für AuthenticationContext ein Authentifizierungsereignis ist.


Methoden:

AquireToken – für OAuth, gibt ein AuthenticationResult zurück, das den aktualisierten Token und den Zugriffstoken für den aktuellen Authentifizierungskontext enthält.

Authentication initialisiert eine Instanz dieser Klasse mithilfe des Configuration-Parameters.

DiscoverAuthority – Authentifizierungsbehörde des Upgradeplans des Dynamics 365-Webdiensts.


OAuthMessageHandler-Klasse

Diese geschachtelte Klasse legt die Autorisierungskopfzeile für jede gesendete Nachricht für Dynamics 365 (Online) und die IFD-Bereitstellung fest.

Verwendung

Die Configuration und Authentication-Klassen sind so konzipiert, dass sie im Tandem verwendet werden, um eine sichere Verbindung zum Ziel Dynamics 365-Service einzurichten. Erstellen Sie zuerst ein Objekt vom Typ Configuration, und führen ihn als einzelnen Parameter für den Authentication-Konstruktor fort. Nach der erfolgreichen Erstellung können Sie die ClientHandler-Eigenschaft verwenden, um eine sichere, authentifizierte, dauerhafte HTTP Client-Verbindung zum Dynamics 365-Service herzustellen.

Eine gebräuchliche Möglichkeit, um diesen Vorgang zu erzielen, der durch die meisten Web API C#-Beispiele verwendet wird, ist, die abgeleitete Klasse FileConfiguration zu verwenden, um Informationen von ordnungsgemäß erstellten Anwendungskonfigurationsdateien zu lesen, wie in der Darstellung in den folgenden Zeilen veranschaulicht.

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

Weitere Informationen finden Sie im Abschnitt FileConfiguration-Verbindungseinstellungen Obwohl die Authentication-Klasse mehrere öffentliche Eigenschaften und Methoden enthält, werden diese hauptsächlich bereitgestellt, um die Erstellung der ClientHandler-Eigenschaft zu unterstützen. Der Zugriff erfolgt selten direkt über die meisten Clientanwendungen.

Klassenlisten

Den aktuellen Code für diese Klasse finden Sie im CRM SDK Web API Helper Library NuGet-Paket.

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);
            }
        }
    }
}

Siehe auch

Erste Schritte mit dem Microsoft Dynamics 365 Web API (C#)
Starten eines Dynamics 365-Web-API-Projekts in Visual Studio (C#)
Verwenden Sie die Microsoft Dynamics 365 WEB API Hilfe-Bibliothek (C#)
Web API-Hilfecode: Konfigurationsklassen
Web API-Hilfecode: CrmHttpResponseException-Klasse

Microsoft Dynamics 365

© 2017 Microsoft. Alle Rechte vorbehalten. Copyright