おでんはじめました。

required ちくわぶ and 巾着,optional はんぺん.

Xamarin.Forms で使える Azure AD 認証付きの WebAPI を実装するには

この記事は Xamarin Advent Calendar 2019 の 9 日目の記事です。

タイトルを実装するのにこれといったベストプラクティスが見つからずになかなかハマりました。

というテーマで、昨日登壇させていただいたのでその最後のベストプラクティスを手順にしてみました。

www.slideshare.net

Azure AD にアプリケーションを登録する

Azure Portal から Azure AD のアプリケーションを登録します。

f:id:masatoru:20191201112114p:plain

  • 概要でアプリケーションID(クライアントID)とディレクトリ(テナントID)をコピペします(後で使います)

  • 認証→リダイレクトURImsal9999...://auth とあるところにチェックを入れて→保存をクリック これが Xamarin 用のリダイレクト URI になります。

f:id:masatoru:20191201113621p:plain

  • 証明書とシークレットで、新しいクライアントシークレットをクリック→任意の名前(secret など)→有効期限なし→追加 これをコピペします。

AppService に認証(EasyAuth)を設定する

AppService は作成済みとして、ポータルから AppService のサイトに移動します。

  • 認証/承認をクリック
  • App Service 認証を ON
  • Azure Active Directory をクリック
  • クライアント ID 、クライアントシークレット(上記で取得済み)をコピペ
  • 発行者の URL はテナント ID (上記で取得済み)を使って以下をコピペ https://login.microsoftonline.com/{テナントID}/v2.0/.well-known/openid-configuration
  • 許可されるトークン対象ユーザーは以下の形式でコピペ https://{Your AppService}.azurewebsites.net/.auth/login/aad/callback
  • OK をクリック
  • 要求が承認されない場合に実行するアクション→ Azure Active Directory でのログイン を選択(忘れやすいので注意!) → 保存をクリック

f:id:masatoru:20191210085138p:plain

Xamarin.Forms にログインを実装する

ログイン画面を実装して API で使用するアクセストークンを取得します。

比較的簡単に実装できる AppCenter Auth は Azure AD B2C のみ対応なので(2019年12月1日現在)使えない(ちなみにロードマップには Azure AD があるので近々対応されるはず)。

となると、Xamarin.Forms(以下 Xamarin ) の場合 MSAL(Microsoft Authentication Library)一択になるわけですが、最初はログイン画面に遷移して2回目以降はキャッシュを取得して画面遷移しないみたいな感じで書きます。この時、ログイン情報をキャッシュするとか有効期限を更新するとかはライブラリにお任せです。

MSAL は nuget から Microsoft.Identity.Client(バージョンは 4.1.0 )で取得します。

using Microsoft.Identity.Client;
// ログインしてアクセストークンを取得する
private async string SignInAsync()
{
  AuthenticationResult authResult = null;
  try
  {
    // キャッシュにあればログイン画面に遷移しない
    IAccount firstAccount = accounts.FirstOrDefault();
    authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
                          .ExecuteAsync();
  }
  catch (MsalUiRequiredException ex)
  {
    try
    {
      // なければログイン画面に遷移する
      authResult = await App.PCA.AcquireTokenInteractive(App.Scopes)
                                  .WithParentActivityOrWindow(App.ParentWindow)
                                  .ExecuteAsync();
    }
    catch (Exception ex2)
    {
    }
  }
  return authResult?.AccessToken;
}

Xamarin で認証付き WebAPI をたたく

取得したアクセストークンを Bearer で渡して WebAPI を叩きます。

最近は HttpClientusing で囲うと犯罪者扱いされるみたいですが...(ry

using (var client = new HttpClient())
{
  // アクセストークンを使ってAPIをたたく
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
  var res = await client.GetAsync(apiUrl);

  if (!res.IsSuccessStatusCode)
  {
    throw new Exception(res.ToString());
  }
  // 結果のJSONを受け取る
  var resultText = await res.Content.ReadAsStringAsync();
...

Azure AD の認証付き WebAPI を実装する

VSCodeASP.Net Core で Azure AD 認証付きの Web API を作成します。

azure-v2-app というアプリを作る場合、コンソールから以下をたたきます。

mkdir azure-v2-app
cd  azure-v2-app
dotnet new webapi
code -r .

VSCode が起動するので、表示→ターミナルを開いて、

dotnet build
dotnet run

これで VSCode がローカルでサーバーを実行している状態になるので、ブラウザや POSTMAN などで、

https://localhost:5001/WeatherForecast

とたたくと JSON が返ってくるはずです。これを Azure の AppService にデプロイします。

  • VSCode拡張機能で Azure App Service を追加します(入れてない場合は)。
  • VSCode の左側の Azure のロゴをクリックして、デプロイする App Service を選択します
  • 右クリックで Deploy to Web App をクリックするとデプロイされます(初回はいくつか質問されますがそのまま OK をクリック)。

API を POSTMAN でテストする

デプロイした WebAPI は EasyAuth で認証されたサイトになっているので、そのままたたくと401( Unauthorized )が返ってきます。 これにトークンを設定して 200 が返ってくれば OK ということになります。

まずはブラウザを使って id_token を取得します。 - 作成したサイトが https://azuread-v2-app.azurewebsites.net であれば、https://azuread-v2-app.azurewebsites.net/WeatherForecast にブラウザでアクセスします - ログインされていなければ Azure AD のログイン画面に遷移します。ログイン済みであれば白い画面が表示されます - 同じ画面で、https://azuread-v2-app.azurewebsites.net/.auth/me とたたくとトークンが取得できるので id_token をコピーします

f:id:masatoru:20191210083212p:plain

次に POSTMAN を使って認証済みのサイトにアクセスしてみます。 - POSTMAN で URL に https://azuread-v2-app.azurewebsites.net/WeatherForecast をコピペ - Authorization → Bearer Token → id_token をコピペ - Send をクリックして ステータスが 200(OK) と JSON が返ってくればOKです。

取得したアクセストークンを調べる

取得した id_tokenaccess_tokenhttps://jwt.ms/ にコピペするとトークンの中身を確認することができます。

MSAL で Azure AD の認証を行う場合 V2 のエンドポイントである必要があるので、 isshttps://login.microsoftonline.com/{テナントID}/v2.0 であることを確認します。ちなみに、V1 のエンドポイントは https://sts.windows.net/{テナントID}/

Xamarin.Forms のソースコード

これで Xamarin.Forms から 認証付き WebAPI をたたけるようになったはずです。あとで Xamarin.Forms のサンプルを GitHub にあげます。

さいごに

401(Unauhtorized)なんて怖くない!より良い認証ライフを!!