웹 API 도우미 코드: 인증 클래스
게시 날짜: 2017년 1월
적용 대상: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online
Authentication 클래스를 사용하여 Microsoft Dynamics 365 웹 서비스에 대해 유효한 연결을 구축합니다. 이 클래스는 Dynamics 365 온-프레미스에 대한 Windows 인증 또는 Dynamics 365(온라인) 또는 인터넷 연결 배포(IFD)에 대한 OAuth 2.0 등 두 가지 인증 프로토콜을 지원합니다. 이 클래스는 Microsoft Azure Active Directory 인증 라이브러리(ADAL)를 기반으로 OAuth 프로토콜을 처리합니다.
Authentication 클래스는 CRM SDK 웹 API 도우미 라이브러리의 Authentication.cs 파일에 있습니다. 개체 유형 System.Net.Http.HttpMessageHandler를 통해 Dynamics 365 서비스에 대한 안전한 연결을 구축하도록 Configuration 도우미 클래스 계층 구조와 함께 작동하도록 설계되었습니다. 자세한 내용은 Microsoft Dynamics 365 웹 API 도우미 라이브러리(C#) 사용을 참조하십시오.
인증 처리
Authentication 클래스가 Dynamics 365 서비스 인증을 위해 사용하는 메커니즘은 Configuration 매개 변수로 생성자에 전달하는 정보에 따라 다릅니다. System.Net.Http.HttpClient 인스턴스를 인스턴스화하기 위해 사용할 수 있는 HttpMessageHandler에서 파생된 개체 구축을 시도합니다. 이로 인해 Dynamics 365 서비스와 안전하고 지속적인 통신 세션을 제공할 수 있습니다.
먼저 OAuth 또는 Windows 전용 인증의 사용 여부를 확인하기 위해 지정된 Dynamics 365 서비스에 대한 간단한 검색 핸드셰이크가 수행됩니다.
OAuth를 사용하는 경우 핸드셰이크에서 발견된 인증 기관을 사용하여 OAuthMessageHandler 개체가 만들어집니다. System.Net.Http.DelegatingHandler에서 파생된 이 클래스는 모든 요청에서 OAuth 액세스 토큰을 새로 고칩니다. 따라서 토큰 만료를 명시적으로 관리할 필요가 없습니다.
Windows 인증을 사용 중이며 및 사용자 자격 증명이 제공된 경우 이러한 자격 증명이 HttpClientHandler를 만들기 위해 사용됩니다.
Windows 인증을 사용 중이나 및 사용자 자격 증명이 제공되지 않은 경우 기본 네트워크 자격 증명을 사용하여 HttpClientHandler가 구축됩니다.
클래스 계층 구조 및 구성원
다음 표에서 Authentication 클래스의 공통 구성원을 보여줍니다.
인증 클래스 속성: Authority - OAuth 인증을 관리하는 서버의 URL입니다. ClientHandler - 메시지 요청에 대한 네트워크 자격 증명 또는 권한 부여 액세스 토큰을 제공하는 HttpMessageHandler에서 파생된 개체입니다. Context - 인증 이벤트에 대한 AuthenticationContext입니다.
AquireToken - OAuth의 경우 현재 인증 컨텍스트에 대한 새로 고침 및 액세스 토큰을 포함하는 AuthenticationResult를 반환합니다. Authentication - Configuration 매개 변수를 사용하여 이 클래스의 인스턴스를 초기화합니다. DiscoverAuthority - Dynamics 365 웹 서비스의 인증 기관을 검색합니다.
OAuthMessageHandler 클래스 이 중첩된 클래스는 Dynamics 365(온라인) 및 IFD 배포에 대해 보낸 각 메시지에 대해 인증 헤더를 설정합니다. |
사용법
Configuration 및 Authentication 클래스는 대상 Dynamics 365 서비스에 대한 보안 연결을 설정하는 데 동시에 사용할 수 있도록 고안되었습니다. 먼저 Configuration 유형의 개체를 만든 다음 Authentication 생성자에 단일 매개 변수로 전달합니다. 성공적으로 만든 후 Dynamics 365 서비스에 대해 지속적인 인증된 보안 HTTP 클라이언트 연결을 구축하기 위해 ClientHandler 속성을 사용할 수 있습니다.
가장 일반적으로 대부분의 웹 API C# 샘플을 사용하는 이 작업을 수행하려면 다음 줄에서 볼 수 있듯이 파생된 클래스 FileConfiguration을 사용하여 적절히 작성된 응용 프로그램 구성 파일에서 연결 정보를 읽습니다.
FileConfiguration config = new FileConfiguration(null);
Authentication auth = new Authentication(config);
httpClient = new HttpClient(auth.ClientHandler, true);
이러한 사용 방법에 대한 자세한 내용은 FileConfiguration 연결 설정 섹션을 참조하십시오.Authentication 클래스에는 여러 다른 공용 속성 및 메서드가 포함되어 있지만 기본적으로 ClientHandler 속성을 만드는 작업을 지원하기 위해 제공되며 대부분의 클라이언트 응용 프로그램에서 직접 액세스할 수 없습니다.
클래스 목록
이 클래스에 대한 최신 정보는 CRM SDK 웹 API 도우미 라이브러리 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);
}
}
}
}
참고 항목
Microsoft Dynamics 365 웹 API(C#) 시작
Visual Studio(C#)에서 Dynamics 365 웹 API 프로젝트 시작
Microsoft Dynamics 365 웹 API 도우미 라이브러리(C#) 사용
웹 API 도우미 코드: 구성 클래스
웹 API 도우미 코드: CrmHttpResponseException 클래스
Microsoft Dynamics 365
© 2017 Microsoft. All rights reserved. 저작권 정보