AADアプリケーションと認可サーバーを理解する（その１のおまけ。.NET Coreアプリケーションに改造）


#はじめに

別の記事、[AADアプリケーションと認可サーバーを理解する（その１）](https://qiita.com/yoshiwatanabe/items/88c3485a7fc5b060f697) からの派生記事です。

あちらの記事ではコンソールアプリケーションを.NET Framework向け（Windowsプラットフォームのみ。Windows環境のみ実行可能）としていましたが、この記事では.NET Core向け（クロスプラットフォーム対応。Windows環境、Linux環境、もしくはMac環境で実行可能）に書き換えて、その上で実際に実行してユーザー体験を確認します。

クロスプラットフォームということで、ちょっと面白い感じのユーザー体験になることが分かりました。

プロジェクトが.NET Framework向けか、.NET Core向けかの違い以外は[AADアプリケーションと認可サーバーを理解する（その１）](https://qiita.com/yoshiwatanabe/items/88c3485a7fc5b060f697) と内容は全く同じです。

# .NET Core向けコンソールアプリケーションに変更する

変更後のプロジェクトファイルを以下に示します。

```xml:aad-client-console.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <RootNamespace>aad_client_console</RootNamespace>
  </PropertyGroup>

    <ItemGroup>
    <PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="[3.19.3,4)" />
    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
    <PackageReference Include="System.Net.Http" Version="4.3.3" />
  </ItemGroup>

</Project>
```

変更箇所は1か所だけです。`<TargetFramework>`タグの値が`net47`から`netcoreapp2.1`になっただけです。

次に`Program.cs`がどのように変更されたか見てみましょう。

```c#:Program.cs
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

namespace aad_client_console
{
    class Program
    {
        static void Main(string[] args)
        {
            var authContext = new AuthenticationContext("https://login.microsoftonline.com/あなたのテナント名.onmicrosoft.com");

            var codeResult = authContext.AcquireDeviceCodeAsync("https://graph.microsoft.com/", "b0905193...で始まるGUID").Result;
                Console.ResetColor();
                Console.WriteLine("You need to sign in.");
                Console.WriteLine("Message: " + codeResult.Message + "\n");

            var authResult = authContext.AcquireTokenByDeviceCodeAsync(codeResult).Result;

            Console.WriteLine("ID token: " + authResult.IdToken);
            Console.WriteLine("Access token: " + authResult.AccessToken);

            var request = new HttpRequestMessage(HttpMethod.Get, $"https://graph.microsoft.com/v1.0/users?$filter=givenName eq 'Tsuyoshi'");
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
            
            var client = new HttpClient();
            var response = client.SendAsync(request).Result;

            Console.WriteLine("User: " + response.Content.ReadAsStringAsync().Result);
        }
    }
}
```
ここでは`authRequest`の取得方法が

```
            var authResult = authContext.AcquireTokenAsync(
                    "https://graph.microsoft.com",
                    "b0905193...で始まるGUID",
                    new Uri("https://あなたのテナント名.onmicrosoft.com/my-aad-client-console"),
                    new PlatformParameters(PromptBehavior.Always)).Result;
```

から

```
            var codeResult = authContext.AcquireDeviceCodeAsync("https://graph.microsoft.com/", "b0905193...で始まるGUID").Result;
                Console.ResetColor();
                Console.WriteLine("You need to sign in.");
                Console.WriteLine("Message: " + codeResult.Message + "\n");

            var authResult = authContext.AcquireTokenByDeviceCodeAsync(codeResult).Result;

```
に変わりました。

特に興味深い点は、まず`codeResult`というデータを取得して、そのデータの`Message`プロパティをコンソールに表示しています。その内容は以下のようなものです。

```
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code B5YZPWJYR to authenticate.
```
メッセージは、認証するにはブラウザで`https://microsoft.com/devicelogin`に行って、B5YZPWJYRを入力せよ、と言っています。これはいったいどういうことでしょう？

このメッセージをコンソールに表示することで、ユーザーに任意のブラウザを使って認証を完了してくださいと指示する必要があるのです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/c8c98bf7-9066-f6d9-8abb-feb0c16db30f.png)

> Windows環境依存の.NET Framework向けのアプリケーションの場合はポップアップウィンドウを利用してユーザー認証を行いましたが、.NET Core向けのアプリケーションの場合ポップアップウィンドウは使えません。ですから、ユーザーには、どのマシーンのどのブラウザでも構わないので、このコードを入力させることで認証ステップを完了させようとしているのです。ところでブラウザは、このコンソールアプリケーションが実行しているマシーン上で実行する必要はありません。手持ちのスマフォのブラウザを使うことも出来ます。

実際に、一連の認証の流れ（シナリオ）を見ていきましょう。

まずは、ブラウザにしてされたアドレスを入力して、ページをロードします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/b2e95f0d-cc4a-b61a-c149-3cf8bea67e1a.png)

コードの入力を求めているので、指示通りに入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/b6246e9d-e210-f392-e78b-5b1fc00fd9a1.png)

するとお馴染みのログインページがでました。ここでAAD認可サーバーに「認証」をしてもらいます。この段階で、アプリケーションがmy-aad-client-consoleであると明示されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/86d78771-f9e9-b7df-a367-628cd7bb5e37.png)

「認証」が完了すると、my-aad-client-consoleへの認可も完了します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/f26a5cc2-8351-6567-01b9-efa75e723507.png)

ところで、コードはユーザーの認可サーバーとのやり取りを、以下のコードの位置で待っています。

```
var authResult = authContext.AcquireTokenByDeviceCodeAsync(codeResult).Result;
```

ユーザーの認証と認可が完了したので、晴れて`authResult`に値が返され、IDトークンとアクセストークンを取得することができました。Microsoft Graph APIを利用するコードについては変更はありません。

以下、プログラムの出力です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/08928980-4b4b-8c78-2f99-4594e7b7f01a.png)

# まとめ

[AADアプリケーションと認可サーバーを理解する（その１）](https://qiita.com/yoshiwatanabe/items/88c3485a7fc5b060f697) で解説したAAD側のAADアプリケーション・オブジェクトの設定そのままで、クライエントのアプリケーションをクロスプラットフォームにすることが出来ました。