Code d'assistance de l'API Web : Classe Authentication
Date de publication : janvier 2017
S’applique à : Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online
Utilisez la classe Authentication pour aider à établir une connexion validée à un service Web Microsoft Dynamics 365. Cette classe prend en charge deux protocoles d'authentification : Authentification Windows pour Dynamics 365 local ou OAuth 2.0 pour Dynamics 365 (online) ou des déploiements avec accès via Internet (IFD). Cette classe s'appuie sur la bibliothèque d'authentification Microsoft Azure Active Directory (ADAL) pour gérer le protocole OAuth.
La classe Authentication se situe dans le fichier Authentication.cs de la Bibliothèque d'aide de l'API Web du Kit de développement logiciel (SDK) CRM Elle este conçu pour être utilisée conjointement avec la hiérarchie des classes d'aide Configuration qui permettent de créer une connexion sécurisée à votre service Dynamics 365 via un objet de type System.Net.Http.HttpMessageHandler Pour plus d'informations, voir Utiliser la bibliothèque d'aide de l'API Web Microsoft Dynamics 365 (C#).
Traitement de l’authentification
Le mécanisme que la classe Authentication utilise pour s'authentifier auprès d'un service Dynamics 365 dépend des informations que vous transmettez au constructeur avec le paramètre Configuration. Il tente de créer un objet dérivé de HttpMessageHandler que vous pouvez alors utiliser pour instancier une instance de System.Net.Http.HttpClient pour fournir une session de communication sécurisée et persistante avec le service Dynamics 365.
Une brève prise de contact de découverte est effectuée avec le service Dynamics 365 spécifique pour déterminer si l'authentification native OAuth ou Windows est utilisée.
Si OAuth est utilisé, un objet OAuthMessageHandler est créé à l'aide de l'autorité d'authentification qui a été détectée dans la prise de contact. Cette classe, dérivée de System.Net.Http.DelegatingHandler actualise le jeton d'accès OAuth à chaque demande, afin que vous ne deviez pas gérer explicitement l'expiration du jeton.
Si l'authentification Windows est utilisée, et que des informations d'identification d'utilisateur sont fournies, ces informations d'identification sont utilisées pour créer un HttpClientHandler.
Si l'authentification Windows est utilisée, mais que des informations d'identification d'utilisateur ne sont pas fournies, un HttpClientHandler est construit à l'aide des informations d'identification réseau par défaut.
Hiérarchie et membres de classe
Le tableau suivant présente les membres de la classe Authentication.
Classe d’authentification Propriétés : Authority – URL du serveur qui gère l'authentification OAuth. ClientHandler - objet dérivé de HttpMessageHandler qui fournit les informations d'identification réseau ou le jeton d'accès d'autorisation pour les demandes de messages. Context – AuthenticationContext d'un événement d'authentification.
AquireToken – Pour OAuth, renvoie un AuthenticationResult, contenant les jetons d'actualisation et d'accès, pour le contexte d'authentification actuel. Authentication – initialise une instance de cette classe en utilisant le paramètre Configuration. DiscoverAuthority – Détecte l'autorité d'authentification du service Web de Dynamics 365.
Classe OAuthMessageHandler Cette classe imbriquée définit l'en-tête d'autorisation de chacun des messages envoyés pour Dynamics 365 (online) et les déploiements IFD. |
Utilisation
Les classes Configuration et Authentication sont conçues pour être utilisées en tandem pour établir une connexion sécurisée avec le service Dynamics 365 cible. Vous créez d'abord créer un objet de type Configuration, puis le transmettre en tant que paramètre unique au constructeur Authentication. Une fois la création réussie, vous pouvez utiliser la propriété ClientHandler pour créer une connexion client HTTP sécurisée, authentifiée, persistante avec le service de Dynamics 365.
La manière habituelle d'accomplir cette opération, utilisée par la plupart des exemples C# de l'API Web, consiste à utiliser la classe dérivée FileConfiguration pour lire les informations de connexion à partir de fichiers de configuration d'application correctement créés, comme illustré dans les lignes suivantes.
FileConfiguration config = new FileConfiguration(null);
Authentication auth = new Authentication(config);
httpClient = new HttpClient(auth.ClientHandler, true);
Pour plus d'informations sur cette utilisation, reportez-vous à la section Paramètres de connexion FileConfiguration. Bien que la classe Authentication contienne plusieurs autres propriétés et méthodes publiques, elles sont principalement fournies pour prendre en charge la création de la propriété ClientHandler, et sont rarement directement accessibles pour la plupart des applications clientes.
Liste des classes
La source la plus récente pour cette classe est disponible dans le package NuGet Bibliothèque d'aide de l'API Web du Kit de développement logiciel (SDK) de CRM.
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);
}
}
}
}
Voir aussi
Se familiariser avec l'API Web Microsoft Dynamics 365 (C#)
Démarrer un projet de l'API Web de Dynamics 365 dans Visual Studio (C#)
Utiliser la bibliothèque d'aide de l'API Web Microsoft Dynamics 365 (C#)
Code d'aide de l'API Web : classes de configuration
Code d'assistance de l'API Web : Classe CrmHttpResponseException
Microsoft Dynamics 365
© 2017 Microsoft. Tous droits réservés. Copyright