Static Web AppsのAPIとしてAzure App Serviceを使い、そこで認証情報を取得する際にハマったこと

2023年6月17日

Static Web Appsを用いてAzure AD B2Cを使ったログイン機能の実装に取り組んでいます。Static Web Appsは、単体では静的ページであり動きがないため、基本的にはAPIを利用して動きをつけることになると思います。そこで、Azure FunctionsやAzure App ServiceをAPIとして利用します。

今回、私がハマった部分は、Static Web Appsで認証を行い、その認証情報をAzure App Service側で受け取ることでした。リクエストヘッダーに含まれるX-MS-CLIENT-PRINCIPAL-NAMEというやつです。ログインユーザーのユーザ名を使用することが目的でした。

結論としては、以下の3つの条件を満たす必要があります。

  1. Static Web Appsをスタンダードプランに設定する。
  2. Static Web AppsとAzure App Serviceをリンクさせる。(Portalからリンクすると、自動的に次の認証プロバイダーも設定されます。)
  3. Static Web Appsで認証プロバイダーの設定を行う。

上記の条件から第三の項目を削除した結果、Static Web Appsでログインして認証情報を取得することができなくなってしまいました。

上記条件以外にも、Static Web AppsのAPI 制約については確認しておいた方が良さそうです。

Pythonのfast apiを使って以下のようなコードを書いています。
x_ms_client_principal_nameに値が入っていることが期待されます。

from typing import Optional
from fastapi import Header
@router.get("/sample")
async def hoge(x_ms_client_principal_name: Optional[str] = Header(None)):
    print(f"x_ms_client_principal_name: {x_ms_client_principal_name}")

さて、これ以降で実際に設定する内容を詳しくみていきます。

設定関連

Static Web Appsのプランをスタンダードにする

まずは、Static Web Appsのプランをスタンダードにします。これをしないとAPIとのリンクでティックAzure App Serviceを選択することができません。

Static Web AppsでAPIのリンクを設定

次はStatic Web AppsでAPIのリンクを設定します。設定メニューのAPIを選択します。リンクと言う部分があるのでクリックします。

新しいバックエンドをリンクすると言う画面が出てくるので、ここで対象となるAzure App Serviceを選択します。

バックエンドリソースの種類は、Azure App ServiceだとWebを選択することになります。

登録すると以下のようになります。

認証のIDプロバイダーを確認と動作検証

Azure App Serviceサービス側を確認します。既にリンク済みであれば、設定の認証で以下のように表示されているはずです。idプロバイダーでStatic Web Appsが選択されています。

この状態でAzure App Serviceの概要にあるURLから、もともとアクセスできていたところを開いてみてください。アクセスできなくなっていると思います。これはリンクしたことによって、このURLに直接アクセスできなくなったためと思ってもらえばいいです。

公式では以下のように記述されています。

リンク プロセスが完了すると、/api で始まるルートへの要求は、リンクされた App Service アプリにプロキシされます。

ではどのようにしてアクセスするかというと、Static Web Appsで使われているURL経由でアクセスします。

Azure App ServiceのURLがStatic Web AppsのURLに統合されたみたいなものです。なので、以下、URLより今までアクセスしていたURLにアクセスしてください。

開発中はいろいろ不便があるので、認証を外して実装することがあります。以下のようにしてIDプロバイダーの認証を外せば、もともとのURLも使用することができます。

認証の削除をするとこんな画面になります。

認証があるときは、このようにエラーの画面でした。

認証を削除したら、このようにちゃんと今までアクセスできていたページが表示されるようになりました。

ドキュメントを読んでいて勘違いしたところ

Azure Functions バックエンドのみユーザクレイムが取得できるのか?

こちらのドキュメントをまず読みました。
[Azure Static Web Apps でのユーザー情報へのアクセス]

https://learn.microsoft.com/ja-jp/azure/static-web-apps/user-information?tabs=javascript

API 関数の項目で以下の記述がありました。

Azure Functions バックエンドを介して Static Web Apps で使用できる API 関数では、claims 配列を除き、クライアント アプリケーションと同じユーザー情報にアクセスできます。

結果的に、App Serviceからも取得できるというのがわかりましたが、Azure Functions バックエンドを介してという部分で制限なのかと思いました。

或いは、ここでのAzure Functions バックエンドという部分については、こちらで言及されているマネージド APIのことなのかもしれません。

IDプロバイダーによる認証を解除してもアクセスがプロキシーされて認証情報が入ってくる

これが今回の勘違いの元だと思います。

よくよくドキュメントを読んでみると、確かに以下の部分があります。

リンク解除プロセスが完了すると、/api で始まるルートへの要求は、App Service アプリにはプロキシされなくなります。

https://learn.microsoft.com/ja-jp/azure/static-web-apps/apis-app-service

つまり、直接ブラウザからApp ServiceのURLを叩いているだけということでしょうか。(そう解釈しました。)

参考URL

今回の件にも絡む内容で、Static Web AppsのAPIでネットワーク分離されたバックエンドとAzure Static Web Appsの統合をどうするか考察している記事。セキュリティガチガチにする時に参考になるなーと思っている。

https://techcommunity.microsoft.com/t5/apps-on-azure-blog/integrating-network-isolated-backends-with-azure-static-web-apps/ba-p/3721136