Del via


Web API Helper-kode: godkendelsesklasse

 

Udgivet: januar 2017

Gælder for: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Brug Authentication-klassen som hjælp ved fastlæggelse af en godkendt forbindelse til en Microsoft Dynamics 365-webtjeneste. Denne klasse understøtter to godkendelsesprotokoller: Windows-godkendelse til Dynamics 365 til det lokale miljø eller OAuth 2.0 til Dynamics 365 (online) eller installation med adgang via internet (IFD'er). Denne klasse er afhængig af Microsoft Azure Active Directory Authentication Library(ADAL) til at håndtere OAuth-protokollen.

Authentication-klassen er placeret i filen Authentication.cs i CRM SDK Web API-hjælperbibliotek. Den er udviklet til at arbejde sammen med Configuration-hjælper klassehierarki, så du kan oprette en sikker forbindelse til Dynamics 365-tjenesten gennem et objekt af typen System.Net.Http.HttpMessageHandler. Du kan finde flere oplysninger under Brug af Microsoft Dynamics 365 Web API Helper-bibliotek (C#).

Godkendelsesbehandling

Den mekanisme, som Authentication-klassen bruger til at godkende med en Dynamics 365-tjeneste, afhænger af de oplysninger, du videregiver til konstruktør med Configuration-parameteren. Den forsøger at opbygge et HttpMessageHandler-afledt objekt, som du derefter kan bruge til at instantiere en forekomst af en System.Net.Http.HttpClient for at opnå en sikker, vedvarende kommunikationssession med Dynamics 365-tjenesten.

Først udføres et kort discovery-handshake med den angivne Dynamics 365-tjeneste for at bestemme, om der bruges oprindelig OAuth- eller Windows-godkendelse.

  • Hvis der bruges OAuth, oprettes der et OAuthMessageHandler-objekt ved hjælp af det nøglecenter, der opdagede handshaket. Denne klasse, der er afledt af System.Net.Http.DelegatingHandler, opdaterer OAuth-adgangstokenet i hver anmodning, så du ikke behøver at administrere tokenudløb udtrykkeligt.

  • Hvis der bruges Windows-godkendelse, og brugerens legitimationsoplysninger er angivet, bruges disse legitimationsoplysninger til at opbygge en HttpClientHandler.

  • Hvis der bruges Windows-godkendelse, men brugerens legitimationsoplysninger ikke er angivet, bruges standardlegitimationsoplysningerne til netværket til at opbygge en HttpClientHandler.

Klassehierarki og medlemmer

Følgende tabel viser de offentlige medlemmer af Authentication-klassen.

Godkendelsesklassediagram til Dynamics 365 Web API Helper-bibliotek

Godkendelsesklasse

Egenskaber:

Authority – URL-adressen på den server, der styrer OAuth-godkendelse.

ClientHandler – det HttpMessageHandler-afledte objekt, der indeholder legitimationsoplysningerne til netværket eller godkendelsesadgangstokenet til anmodninger om meddelelser.

ContextAuthenticationContext for godkendelseshændelsen.


Metoder:

AquireToken – For OAuth, returnerer en AuthenticationResult, der indeholder opdaterings- og adgangtokens for den aktuelle godkendelseskontekst.

Authentication – Starter en forekomst af denne klasse ved hjælp af Configuration-parameteren.

DiscoverAuthority – Opdager nøglecenteret på Dynamics 365-webtjenesten.


OAuthMessageHandler-klasse

Denne indlejrede klasse indstiller godkendelses-headeren for hver sendt meddelelse i Dynamics 365 (online)- og IFD-installationer.

Brug

Configuration- og Authentication-klasserne er designet til brug sammen med henblik på oprettelse af en sikker forbindelse til Dynamics 365-destinationstjenesten. Først skal du oprette et objekt af typen Configuration og derefter sende det som enkelt parameter til Authentication-konstruktøren. Efter oprettelsen kan du bruge ClientHandler-egenskaben til at konstruere en sikker, godkendt, vedvarende HTTP-klientforbindelse til Dynamics 365-tjenesten.

En almindelig måde at udføre denne handling på, der bruges af de fleste af Web-API'ens C#-eksempler, er at bruge den afledte klasse FileConfiguration til at læse oplysninger om forbindelsen fra korrekt oprettede programkonfigurationsfiler, som vist i følgende linjer.

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

Du kan finde flere oplysninger om denne brugsmåde i afsnittet Indstillinger for FileConfiguration-forbindelse Selvom Authentication-klassen indeholder flere andre offentlige egenskaber og metoder, er disse primært medtaget for at understøtte oprettelsen af ClientHandler-egenskaben, og kun de færreste klientprogrammer vil have direkte adgang til dem.

Klasseliste

Den mest aktuelle kilde for denne klasse findes i CRM SDK Web API-hjælperbibliotekets NuGet-pakke.

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

Se også

Introduktion til Microsoft Dynamics 365 Web API (C#)
Starte et Dynamics 365 Web API-projekt i Visual Studio (C#)
Brug af Microsoft Dynamics 365 Web API Helper-bibliotek (C#)
Web-API-hjælpekode: konfiguration af klasser
Web API Helper-kode: CrmHttpResponseException-klasse

Microsoft Dynamics 365

© 2017 Microsoft. Alle rettigheder forbeholdes. Ophavsret