次の方法で共有


OAuth 認証を Microsoft Dataverse で使用

OAuth 2.0 は、認証の業界標準プロトコルです。 アプリケーションのユーザーが認証に資格情報を提供した後、OAuth はリソースにアクセスする権限があるかどうかを判断します。

クライアント アプリケーションは、Web API を使用してデータにアクセスする OAuth の使用をサポートする必要があります。 OAuth は、サーバー間アプリケーション シナリオの、2 要素認証 (2FA) または証明書ベースの認証を有効にします。

OAuth では、認証に ID プロバイダーが必要です。 Dataverse については、Microsoft Entra ID が ID プロバイダーとなります。 マイクロソフトの職場または学校アカウントを使用して認証するには、 マイクロソフト認証ライブラリ (MSAL) を使用します。

ヒント

この記事では、認証ライブラリで OAuth を使用して Dataverse に接続する場合に関連する一般的な概念について説明します。 このコンテンツでは、開発者が Dataverse に接続する方法に焦点を当てていますが、OAuth やライブラリの内部動作には焦点を当てません。 認証に関連する詳細については、Microsoft Entra ID のドキュメントを参照してください。 「 認証とは」 の記事を開始することをお勧めします。

提供されているサンプルは、独自のアプリ登録を生成せずに実行できるように、適切な登録値で事前に構成されています。 独自のアプリを公開する場合は、独自の登録値を使用する必要があります。

アプリの登録

OAuth を使用して接続するには、 ご利用の Microsoft Entra ID テナントにてアプリケーションを登録する必要があります。 アプリを登録する方法は、作成するアプリの種類によって異なります。

いずれの場合も、次の記事に記載されたアプリを登録するための基本的な手順から始めます: クイックスタート: アプリケーションを Microsoft ID プラットフォームに登録する。 Dataverse 固有の手順については、「 チュートリアル: Microsoft Entra ID を使用してアプリを登録する」を参照してください。

この手順で行う必要がある決定は、主にアプリケーションの種類の選択によって異なります (次のセクションを参照)。

アプリ登録の種類

Microsoft Entra ID にてアプリケーションを登録する際には、アプリケーションの種別を選択する必要があります。 登録できるアプリケーションには 2 種類あります。

アプリケーションの種類 説明
Web アプリ /API Web クライアント
Web サーバーですべてのコードを実行する クライアント アプリケーション の種類。

ユーザー エージェント ベースのクライアント
Single Page Application (SPA) などの Web サーバーからコードをダウンロードし、ユーザー エージェント内で実行する (たとえば、Web ブラウザー) クライアント アプリケーション の種類。
ネイティブ モード デバイスでネイティブにインストールされる クライアント アプリケーション の種類。

Web アプリ /API を選択する際に、 サインオンするURL を指定する必要があります。これは Microsoft Entra ID が認証の応答を送信するURLであり、認証が成功した際にはトークンが含まれます。 アプリの開発中に、この URL は通常 https://localhost/appname:[port] に設定されるため、アプリをローカルに開発およびデバッグできます。 アプリを公開する場合、アプリの公開された URL へのこの値を変更する必要があります。

ネイティブを選択する場合、リダイレクト URI を提供する必要があリます。 URL は、Microsoft Entra ID が OAuth 2.0 リクエストにて、ユーザエージェントをリダイレクトするために使用する一意の識別子です。 この URL は通常、次のように書式設定された値です: app://<guid>

Dataverse へのアクセス権を付与する

アプリが、認証されたユーザーが操作を実行できるクライアントである場合、アクセス許可を委任された組織のユーザーとして Dynamics 365 にアクセスするようアプリケーションを構成する必要があります。

アクセス許可を設定する具体的な手順については、Microsoft Entra ID でアプリを登録するを参照してください。

アプリがサーバー間 (S2S) の認証を使用する場合、この手順は必要ありません。 この構成には、認証する必要があるユーザーではなく、特定のシステム ユーザーとそのユーザー アカウントによって実行される操作が必要です。

クライアント シークレット & 証明書の使用

サーバー間のシナリオでは、認証する対話型ユーザー アカウントはありません。 このような場合、アプリケーションが信頼できることを確認するためのいくつかの手段を提供する必要があります。 確認は、クライアント シークレットまたは証明書を使用して行われます。

Web アプリ /API アプリケーションの種類で登録されるアプリに関しては、シークレットを構成できます。 これらのシークレットは、アプリ登録の [設定] の [API アクセス] の [キー] 領域を使用して設定されます。

どちらのアプリケーションの種類でも、証明書をアップロードできます。

詳細: アプリとして接続

認証ライブラリを使用して接続する

マイクロソフトがサポートする Microsoft Entra ID 認証クライアント ライブラリのいずれかを使用して、マイクロソフト認証ライブラリ (MSAL) などの Dataverse に接続します。 提供されたリンクでの説明にあるように、このライブラリはさまざまなプラットフォームで利用できます。

ヒント

Microsoft Authentication Library (ADAL) は更新プログラムをアクティブに受信しなくなり、2022 年 6 月までサポートされます。 MSAL は、プロジェクトで使用するように推奨される認証ライブラリです。

Dataverse の認証で MSAL ライブラリを使用する方法を示すコード サンプルについては、クイックスタート サンプルを参照してください。

.NET クライアント ライブラリ

Dataverse は OAuth 2.0プロトコルを使用したWeb APIエンドポイント によるアプリケーション認証をサポートします。 カスタム .NET アプリケーションの場合、Web API エンドポイントでのアプリケーション認証に MSAL を使用します。

.NET 用 Dataverse SDK には認証を処理するクライアント クラス CrmServiceClientServiceClient が含まれます。 現在、CrmServiceClient クラスは認証に ADAL を使用し、ServiceClient は MSAL を使用しています。 これらのクライアントを使用するアプリケーション コードを書き込むと、認証を直接管理する必要がなくなります。 どちらのクライアントも、SDK および Web API エンドポイントで動作します。

要求で AccessToken を使用します

認証ライブラリを使用するポイントは、要求に含めることができるアクセス トークンを取得することです。 トークンを取得するのに必要なコードはわずか数行で、HttpClient がリクエストを実行するよう構成するには、さらに数行を追加するだけです。

重要

この記事のサンプル コードで示されているように、パブリック クライアントには 「<environment-url>/user_impersonation」スコープを使用します。 機密クライアントの場合は、「<environment-url>/.default」 のスコープを使用します。

単純な例

次の例は、1 つの Web API 要求を実行するために必要な最小限のコード量ですが、推奨される方法ではありません。 このコード例では、MSAL ライブラリを使用し、 クイック スタート サンプルから取得します。

string resource = "https://contoso.api.crm.dynamics.com";
var clientId = "51f81489-12ee-4a9e-aaae-a2591f45987d";
var redirectUri = "http://localhost"; // Loopback for the interactive login.

// MSAL authentication
var authBuilder = PublicClientApplicationBuilder.Create(clientId)
    .WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
    .WithRedirectUri(redirectUri)
    .Build();
var scope = resource + "/user_impersonation";
string[] scopes = { scope };

AuthenticationResult token =
    authBuilder.AcquireTokenInteractive(scopes).ExecuteAsync().Result;

// Set up the HTTP client
var client = new HttpClient
{
    BaseAddress = new Uri(resource + "/api/data/v9.2/"),
    Timeout = new TimeSpan(0, 2, 0)  // Standard two minute timeout.
};

HttpRequestHeaders headers = client.DefaultRequestHeaders;
headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
headers.Add("OData-MaxVersion", "4.0");
headers.Add("OData-Version", "4.0");
headers.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

// Web API call
var response = client.GetAsync("WhoAmI").Result;

この単純な方法は、 token が約 1 時間で期限切れになるため、従うのに適したパターンではありません。 MSAL ライブラリはトークンをキャッシュし、 AcquireTokenInteractive メソッドが呼び出されるたびに更新します。 ただし、この単純な例ではトークンを 1 回だけ取得しています。

委任メッセージ ハンドラーを示す例

DelegatingHandlerのコンストラクターに渡される willHttpClient から派生したクラスを実装することをお勧めします。 このハンドラーを使用すると、 HttpClient.SendAsync メソッドをオーバーライドして、http クライアントから送信された各要求で AcquireToken* メソッド呼び出しによってアクセス トークンが更新されるようにすることができます。

次のコードは、 DelegatingHandlerから派生したカスタム クラスの例です。 このコードは、MSAL 認証ライブラリを使用する 拡張クイック スタート サンプルから取得します。

class OAuthMessageHandler : DelegatingHandler
{
    private AuthenticationHeaderValue authHeader;
    public OAuthMessageHandler(string serviceUrl, string clientId, string redirectUrl, string username, string password,
            HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
        string apiVersion = "9.2";
        string webApiUrl = $"{serviceUrl}/api/data/v{apiVersion}/";
        var authBuilder = PublicClientApplicationBuilder.Create(clientId)
                        .WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
                        .WithRedirectUri(redirectUrl)
                        .Build();
        var scope = serviceUrl + "/user_impersonation";
        string[] scopes = { scope };
        // First try to get an authentication token from the cache using a hint.
        AuthenticationResult authBuilderResult=null;
        try
        {
            authBuilderResult = authBuilder.AcquireTokenSilent(scopes, username)
               .ExecuteAsync().Result;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(
                $"Error acquiring auth token from cache:{System.Environment.NewLine}{ex}");
            // Token cache request failed, so request a new token.
            try
            {
                if (username != string.Empty && password != string.Empty)
                {
                    // Request a token based on username/password credentials.
                    authBuilderResult = authBuilder.AcquireTokenByUsernamePassword(scopes, username, password)
                                .ExecuteAsync().Result;
                }
                else
                {
                    // Prompt the user for credentials and get the token.
                    authBuilderResult = authBuilder.AcquireTokenInteractive(scopes)
                                .ExecuteAsync().Result;
                }
            }
            catch (Exception msalex)
            {
                System.Diagnostics.Debug.WriteLine(
                    $"Error acquiring auth token with user credentials:{System.Environment.NewLine}{msalex}");
                throw;
            }
        }
        //Note that an Microsoft Entra ID access token has finite lifetime, default expiration is 60 minutes.
        authHeader = new AuthenticationHeaderValue("Bearer", authBuilderResult.AccessToken);
    }

    protected override Task<HttpResponseMessage> SendAsync(
              HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        request.Headers.Authorization = authHeader;
        return base.SendAsync(request, cancellationToken);
    }
}

この OAuthMessageHandler クラスを使用する場合、単純な Main メソッドは次のようになります。

class Program
{
    static void Main(string[] args)
    {
        try
        {
            //Get configuration data from App.config connectionStrings
            string connectionString = ConfigurationManager.ConnectionStrings["Connect"].ConnectionString;

            using (HttpClient client = SampleHelpers.GetHttpClient(connectionString, SampleHelpers.clientId,
                SampleHelpers.redirectUrl))
            {
                // Use the WhoAmI function
                var response = client.GetAsync("WhoAmI").Result;

                if (response.IsSuccessStatusCode)
                {
                    //Get the response content and parse it.
                    JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
                    Guid userId = (Guid)body["UserId"];
                    Console.WriteLine("Your UserId is {0}", userId);
                }
                else
                {
                    Console.WriteLine("The request failed with a status of '{0}'",
                                response.ReasonPhrase);
                }
                Console.WriteLine("Press any key to exit.");
                Console.ReadLine();
            }
        }
        catch (Exception ex)
        {
            SampleHelpers.DisplayException(ex);
            Console.WriteLine("Press any key to exit.");
            Console.ReadLine();
        }
    }
}

アプリケーション コードでの接続文字列またはユーザー名/パスワード認証の使用については、次の重要な情報をお読みください。

重要

Microsoft では、利用可能な最も安全な認証フローを使用することをお勧めします。 この記事で説明する認証フローは、アプリケーションに対する非常に高い信頼を必要とし、他のフローには存在しないリスクを伴います。 このフローは、マネージド ID など、他のより安全なフローが実行できない場合にのみ使用してください。

構成文字列の値は App.config ファイル接続文字列に移動され、http クライアントは GetHttpClient メソッドで構成されます。

public static HttpClient GetHttpClient(string connectionString, string clientId, string redirectUrl, string version = "v9.2")
{
    string url = GetParameterValueFromConnectionString(connectionString, "Url");
    string username = GetParameterValueFromConnectionString(connectionString, "Username");
    string password = GetParameterValueFromConnectionString(connectionString, "Password");
    try
    {
        HttpMessageHandler messageHandler = new OAuthMessageHandler(url, clientId, redirectUrl, username, password,
                        new HttpClientHandler());

        HttpClient httpClient = new HttpClient(messageHandler)
        {
            BaseAddress = new Uri(string.Format("{0}/api/data/{1}/", url, version)),

            Timeout = new TimeSpan(0, 2, 0)  //2 minutes
        };

        return httpClient;
    }
    catch (Exception)
    {
        throw;
    }
}

完全なコードは 拡張クイックスタート のサンプルを参照してください。

この例では、オーバーライドされたHttpClientではなく GetAsync.SendAsync を使用していますが、要求を送信するHttpClientメソッドにも同じコード フローが適用されます。

アプリとして接続

作成する一部のアプリは、ユーザーが対話形式で実行することを意図していません。 たとえば、Dataverse データに対する操作を実行できる Web クライアント アプリケーションや、あるスケジュールに基づいたタスクを実行するコンソールアプリケーションを作成するなどのケースが考えられます。

一般のユーザーの資格情報を使用してこれらのシナリオを実行することはできますが、そのユーザー アカウントでは有料ライセンスを使用する必要があります。 この方法はお勧めしません。

このような場合は、Microsoft Entra ID 登録済みアプリケーションにバインドされた特別なアプリケーション ユーザーを作成できます。 次に、アプリ用に構成されたキー シークレットを使用するか、 X.509 証明書をアップロードします。 この方法の別の利点は、有料ライセンスを使用しないことです。

アプリとして接続するための要求

アプリとして接続するには、次のものが必要です。

  • 登録済みアプリ
  • 登録されたアプリにバインドされた Dataverse ユーザー
  • アプリケーション シークレットまたは証明書サムプリントのいずれかを使用して接続する

アプリの登録

アプリを登録するときは、「 チュートリアル: Microsoft Entra ID でアプリを登録する」で説明されている同じ手順の多くに従います。ただし、次の例外があります。

  • Access Dynamics 365 に組織ユーザーのアクセス許可を付与する必要はありません。

    このアプリケーションは、特定のユーザー アカウントにバインドされます。

  • アプリ登録のシークレットを構成するか、公開キー証明書をアップロードする必要があります。

アプリ登録の 管理>証明書とシークレットで資格情報を作成または表示できます。

証明書を追加するには (公開キー):

  1. 証明書 タブで、証明書のアップロードを選択します。
  2. アップロードするファイルを選択します。 次のいずれかのファイルの種類である必要があります: .cer、.pem、.crt。
  3. 説明を入力します。
  4. 追加を選択します。

クライアント シークレット (アプリケーション パスワード) を追加するには:

  1. クライアント シークレット タブで、クライアント シークレットの説明を追加します。
  2. 有効期限を選択します。
  3. 追加を選択します。

重要

設定の変更を保存すると、シークレット値が表示されます。 ページを離れるとその値にアクセスできないため、クライアント アプリケーション コードで使用するシークレット値を必ずコピーしてください。

詳細: 資格情報を追加する

登録されたアプリにバインドされた Dataverse のユーザー アカウント

最初に行う必要があるのは、このアカウントが Dataverse 組織内で持つアクセス権と特権を定義するカスタム セキュリティ ロールを作成することです。 詳細: ユーザー定義セキュリティ ロールの作成または編集

カスタム セキュリティ ロールを作成したら、それを使用するユーザー アカウントを作成する必要があります。

Dataverse アプリケーション ユーザーを手動で作成します

アプリケーション ユーザーを作成する手順については、Power Platform の記事の管理: アプリケーションユーザーの作成を参照してください。

アプリケーション ユーザー作成後、アプリケーション ユーザーを作成されたカスタム セキュリティ ロールに関連付けます。

アプリケーション シークレットを使用して接続する

クライアント シークレットを使用して接続し、 Microsoft.Xrm.Tooling.Connector.CrmServiceClient を使用している場合は、次に示すようなコードを使用できます。

string SecretID = "00000000-0000-0000-0000-000000000000";
string AppID = "00001111-aaaa-2222-bbbb-3333cccc4444";
string InstanceUri = "https://yourorg.crm.dynamics.com";

string ConnectionStr = $@"AuthType=ClientSecret;
                        SkipDiscovery=true;url={InstanceUri};
                        Secret={SecretID};
                        ClientId={AppID};
                        RequireNewInstance=true";
using (ServiceClient svc = new ServiceClient(ConnectionStr))
{
    if (svc.IsReady)
    {
    //your code goes here
    }

}

証明書サムプリントを使用して接続する

証明書を使用して接続し、 Microsoft.Xrm.Tooling.Connector.CrmServiceClient を使用している場合は、次に示すようなコードを使用できます。

string CertThumbPrintId = "DC6C689022C905EA5F812B51F1574ED10F256FF6";
string AppID = "00001111-aaaa-2222-bbbb-3333cccc4444";
string InstanceUri = "https://yourorg.crm.dynamics.com";

string ConnectionStr = $@"AuthType=Certificate;
                        SkipDiscovery=true;url={InstanceUri};
                        thumbprint={CertThumbPrintId};
                        ClientId={AppID};
                        RequireNewInstance=true";
using (ServiceClient svc = new ServiceClient(ConnectionStr))
{
    if (svc.IsReady)
    {
    //your code goes here
    }

}

関連項目

Microsoft Dataverse ウェブサービス を使用した認証
.NET Framework アプリケーションを認証する
Microsoft 認証ライブラリの概要