チュートリアル:Azure App Service で CORS を使用して RESTful API をホストする

Azure App Service は、非常にスケーラブルな、自己適用型の Web ホスティング サービスを提供します。 さらに、App Service には、RESTful API 用のクロスオリジン リソース共有 (CORS) の組み込みサポートがあります。 このチュートリアルでは、CORS サポートを使用して ASP.NET Core API アプリを App Service にデプロイする方法について説明します。 コマンドライン ツールを使用してアプリを構成し、Git を使用してアプリをデプロイします。

このチュートリアルでは、以下の内容を学習します。

  • Azure CLI を使用して App Service リソースを作成する
  • Git を使用して RESTful API を Azure にデプロイする
  • App Service の CORS サポートを有効にする

このチュートリアルの手順は、macOS、Linux、Windows で実行できます。

Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。

前提条件

このチュートリアルを完了するには、以下が必要です。

ローカル ASP.NET Core アプリの作成

この手順では、ローカル ASP.NET Core プロジェクトを設定します。 App Service では、他の言語で記述された API についても同じワークフローがサポートされます。

サンプル アプリケーションの複製

  1. ターミナル ウィンドウから、cd コマンドで作業ディレクトリに移動します。

  2. サンプル リポジトリを複製し、リポジトリ ルートに変更します。

    git clone https://github.com/Azure-Samples/dotnet-core-api
    cd dotnet-core-api
    

    このリポジトリには、「Swagger を使用する ASP.NET Core Web API のヘルプ ページ」というチュートリアルに基づいて作成されたアプリが含まれています。 ここでは、Swagger ジェネレーターを使用して Swagger UI と Swagger JSON エンドポイントが提供されます。

  3. 既定のブランチが main であることを確認します。

    git branch -m main
    

    ヒント

    App Service では、ブランチ名の変更は必要ありません。 ただし、多くのリポジトリで既定のブランチが main に変更されているため (「デプロイ ブランチを変更する」を参照)、このチュートリアルでは、main からリポジトリをデプロイする方法も示します。

アプリケーションの実行

  1. 次のコマンドを実行して、必要なパッケージをインストールし、データベースの移行を実行し、アプリケーションを起動します。

    dotnet restore
    dotnet run
    
  2. ブラウザーで http://localhost:5000/swagger に移動して、Swagger UI を起動します。

    ASP.NET Core API running locally

  3. http://localhost:5000/api/todo に移動して、ToDo JSON 項目の一覧を確認します。

  4. http://localhost:5000 に移動して、ブラウザー アプリを起動します。 後で、ブラウザー アプリで App Service のリモート API を参照して、CORS 機能をテストします。 ブラウザー アプリのコードは、リポジトリの wwwroot ディレクトリにあります。

  5. 任意のタイミングで ASP.NET Core を停止するには、ターミナルで Ctrl+C キーを押します。

Azure Cloud Shell

Azure では、ブラウザーを介して使用できる対話型のシェル環境、Azure Cloud Shell がホストされています。 Cloud Shell で Bash または PowerShell を使用して、Azure サービスを操作できます。 ローカル環境に何もインストールしなくても、Cloud Shell にプレインストールされているコマンドを使用して、この記事のコードを実行できます。

Azure Cloud Shell を開始するには、以下のようにします。

オプション 例とリンク
コードまたはコマンド ブロックの右上隅にある [使ってみる] を選択します。 [使ってみる] を選択しても、コードまたはコマンドは Cloud Shell に自動的にはコピーされません。 Screenshot that shows an example of Try It for Azure Cloud Shell.
https://shell.azure.com に移動するか、[Cloud Shell を起動する] ボタンを選択して、ブラウザーで Cloud Shell を開きます。 Button to launch Azure Cloud Shell.
Azure portal の右上にあるメニュー バーの [Cloud Shell] ボタンを選択します。 Screenshot that shows the Cloud Shell button in the Azure portal

Azure Cloud Shell を使用するには、以下のようにします。

  1. Cloud Shell を開始します。

  2. コード ブロック (またはコマンド ブロック) の [コピー] ボタンを選択し、コードまたはコマンドをコピーします。

  3. Windows と Linux では Ctrl+Shift+V キーを選択し、macOS では Cmd+Shift+V キーを選択して、コードまたはコマンドを Cloud Shell セッションに貼り付けます。

  4. Enter キーを選択して、コードまたはコマンドを実行します。

アプリを Azure にデプロイする

この手順では、App Service に .NET Core アプリケーションをデプロイします。

ローカル Git デプロイを構成する

FTP およびローカルの Git では、"デプロイ ユーザー" を使用して Azure Web アプリにデプロイできます。 デプロイ ユーザーを構成すると、すべての Azure デプロイでこのユーザーを使用できます。 アカウントレベルのデプロイのユーザー名とパスワードは、Azure サブスクリプションの資格情報とは異なります。

デプロイ ユーザーを構成するには、Azure Cloud Shell で az webapp deployment user set コマンドを実行します。 <username> と <password> を、デプロイ ユーザーのユーザー名とパスワードで置き換えます。

  • ユーザー名は、Azure 内で一意である必要があり、ローカル Git プッシュの場合は "\@" シンボルを含めることはできません。
  • パスワードは長さが 8 文字以上で、文字、数字、記号のうち 2 つを含む必要があります。
az webapp deployment user set --user-name <username> --password <password>

JSON 出力には、パスワードが null として表示されます。 'Conflict'. Details: 409 エラーが発生した場合は、ユーザー名を変更します。 'Bad Request'. Details: 400 エラーが発生した場合は、より強力なパスワードを使用します。

Web アプリのデプロイに使用するユーザー名とパスワードを記録します。

リソース グループを作成する

リソース グループとは、Web アプリ、データベース、ストレージ アカウントなどの Azure リソースのデプロイと管理に使用する論理コンテナーです。 たとえば、後から簡単な手順で一度にリソース グループ全体を削除することもできます。

Cloud Shell で az group create コマンドを使用して、リソース グループを作成します。 次の例では、myResourceGroup という名前のリソース グループを "西ヨーロッパ" の場所に作成します。 Free レベルの App Service でサポートされているすべての場所を表示するには、az appservice list-locations --sku FREE コマンドを実行します。

az group create --name myResourceGroup --location "West Europe"

通常は、現在地付近の地域にリソース グループおよびリソースを作成します。

コマンドが完了すると、リソース グループのプロパティが JSON 出力に表示されます。

App Service プランを作成する

Cloud Shell で az appservice plan create コマンドを使用して、App Service プランを作成します。

次の例では、myAppServicePlan 価格レベルの myAppServicePlan という名前の App Service プランを作成します。

az appservice plan create --name myAppServicePlan --resource-group myResourceGroup --sku FREE

App Service プランが作成されると、Azure CLI によって、次の例のような情報が表示されます。

{ 
  "adminSiteName": null,
  "appServicePlanName": "myAppServicePlan",
  "geoRegion": "West Europe",
  "hostingEnvironmentProfile": null,
  "id": "/subscriptions/0000-0000/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/myAppServicePlan",
  "kind": "app",
  "location": "West Europe",
  "maximumNumberOfWorkers": 1,
  "name": "myAppServicePlan",
  < JSON data removed for brevity. >
  "targetWorkerSizeId": 0,
  "type": "Microsoft.Web/serverfarms",
  "workerTierName": null
} 

Web アプリを作成する

myAppServicePlan App Service プランで Web アプリを作成します。

Cloud Shell で、az webapp create コマンドを使用することができます。 次の例では、<app-name> をグローバルに一意のアプリ名に置き換えてください (有効な文字は a-z0-9-)。

az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <app-name> --deployment-local-git

Web アプリが作成されると、Azure CLI によって次の例のような出力が表示されます。

Local git is configured with url of 'https://<username>@<app-name>.scm.azurewebsites.net/<app-name>.git'
{
  "availabilityState": "Normal",
  "clientAffinityEnabled": true,
  "clientCertEnabled": false,
  "clientCertExclusionPaths": null,
  "cloningInfo": null,
  "containerSize": 0,
  "dailyMemoryTimeQuota": 0,
  "defaultHostName": "<app-name>.azurewebsites.net",
  "deploymentLocalGitUrl": "https://<username>@<app-name>.scm.azurewebsites.net/<app-name>.git",
  "enabled": true,
  < JSON data removed for brevity. >
}

Note

Git リモートの URL は deploymentLocalGitUrl プロパティに https://<username>@<app-name>.scm.azurewebsites.net/<app-name>.git 形式で出力されます。 この URL は後で必要になるので保存しておいてください。

Git から Azure へのプッシュ

  1. main ブランチをデプロイするため、App Service アプリの既定のデプロイ ブランチを main に設定する必要があります (「main」を参照)。 Cloud Shell で、az webapp config appsettings set コマンドを使用して DEPLOYMENT_BRANCH アプリ設定を設定します。

    az webapp config appsettings set --name <app-name> --resource-group myResourceGroup --settings DEPLOYMENT_BRANCH='main'
    
  2. ローカル ターミナル ウィンドウで、ローカル Git リポジトリに Azure リモートを追加します。 <deploymentLocalGitUrl-from-create-step>を、「Web アプリを作成する」で保存した Git リモートの URL に置き換えます。

    git remote add azure <deploymentLocalGitUrl-from-create-step>
    
  3. アプリをデプロイするために、次のコマンドで Azure リモートにプッシュします。 Git Credential Manager によって資格情報の入力を求めるメッセージが表示されたら、Azure portal へのサインインに使用する資格情報ではなく、「デプロイ ユーザーを構成する」で作成した資格情報を入力してください。

    git push azure main
    

    このコマンドの実行には、数分かかる場合があります。 実行中、次の例のような情報が表示されます。

   Enumerating objects: 83, done.
   Counting objects: 100% (83/83), done.
   Delta compression using up to 8 threads
   Compressing objects: 100% (78/78), done.
   Writing objects: 100% (83/83), 22.15 KiB | 3.69 MiB/s, done.
   Total 83 (delta 26), reused 0 (delta 0)
   remote: Updating branch 'master'.
   remote: Updating submodules.
   remote: Preparing deployment for commit id '509236e13d'.
   remote: Generating deployment script.
   remote: Project file path: .\TodoApi.csproj
   remote: Generating deployment script for ASP.NET MSBuild16 App
   remote: Generated deployment script files
   remote: Running deployment command...
   remote: Handling ASP.NET Core Web Application deployment with MSBuild16.
   remote: .
   remote: .
   remote: .
   remote: Finished successfully.
   remote: Running post deployment command(s)...
   remote: Triggering recycle (preview mode disabled).
   remote: Deployment successful.
   To https://<app_name>.scm.azurewebsites.net/<app_name>.git
   * [new branch]      master -> master
   

Azure アプリを参照する

  1. ブラウザーで http://<app_name>.azurewebsites.net/swagger に移動して、Swagger UI を起動します。

    ASP.NET Core API running in Azure App Service

  2. http://<app_name>.azurewebsites.net/swagger/v1/swagger.json に移動して、デプロイされた API の swagger.json を確認します。

  3. http://<app_name>.azurewebsites.net/api/todo に移動して、デプロイされた API が機能していることを確認します。

CORS 機能の追加

次に、API について App Service の組み込み CORS サポートを有効にします。

サンプル アプリで CORS をテストする

  1. ローカル リポジトリで、wwwroot/index.html を開きます。

  2. 行 51 で apiEndpoint 変数を、デプロイされた API の URL (http://<app_name>.azurewebsites.net) に設定します。 <app_name> は、App Service のアプリ名に置き換えます。

  3. ローカル ターミナル ウィンドウでサンプル アプリをもう一度実行します。

    dotnet run
    
  4. http://localhost:5000 でブラウザー アプリに移動します。 ブラウザーで開発者ツール ウィンドウを開き (Windows 用の Chrome では Ctrl+Shift+i)、 [Console](コンソール) タブを確認します。No 'Access-Control-Allow-Origin' header is present on the requested resource というエラー メッセージが表示されています。

    CORS error in browser client

    ブラウザー アプリ (http://localhost:5000) とリモート リソース (http://<app_name>.azurewebsites.net) のドメインの不一致は、クロス オリジン リソース要求としてブラウザーによって認識されます。 また、App Service アプリの REST API によって Access-Control-Allow-Origin ヘッダーが送信されていないという事実があるため、ブラウザーでクロス ドメイン コンテンツを読み込むことができません。

    運用環境のブラウザー アプリでは localhost URL ではなくパブリック URL が使用されます。しかし、localhost URL に対して CORS を有効にする方法は、パブリック URL の場合と同じです。

CORS を有効にする

Cloud Shell で az webapp cors add コマンドを使用して、クライアントの URL に対して CORS を有効にします。 <app-name> プレースホルダーを置換します。

az webapp cors add --resource-group myResourceGroup --name <app-name> --allowed-origins 'http://localhost:5000'

コマンドを複数回実行するか、--allowed-origins にコンマ区切りリストを追加することで、許可された複数の配信元を追加できます。 すべての配信元を許可するには、--allowed-origins '*' を使用します。

CORS をもう一度テストする

http://localhost:5000 でブラウザー アプリを更新します。 [Console](コンソール) ウィンドウのエラー メッセージは消えており、デプロイされた API からのデータを確認して操作できます。 これで、ローカルで実行されているブラウザー アプリへの CORS がリモート API でサポートされました。

CORS success in browser client

おめでとうございます。CORS サポートを使用して Azure App Service の API が実行されています。

よく寄せられる質問

App Service CORS と独自の CORS

App Service CORS ではなく独自の CORS ユーティリティを使用して、柔軟性を高めることができます。 たとえば、異なるルートまたはメソッドに対して、別の許可されるオリジンを指定したい場合があります。 App Service CORS では、すべての API ルートとメソッドに 1 セットの許可されるオリジンを指定できます。そのため、独自の CORS コードを使用する必要があります。 ASP.NET Core でこれを実行する方法については、「Enabling Cross-Origin Requests (CORS) (クロスオリジン要求の有効化 (CORS))」を参照してください。

組み込みの App Service CORS 機能には、指定した配信元ごとに特定の HTTP メソッドまたは動詞のみを許可するオプションはありません。 定義された配信元ごとにすべてのメソッドとヘッダーが自動的に許可されます。 この動作は、オプション .AllowAnyHeader().AllowAnyMethod() をコードで使用する場合の ASP.NET CORE CORS ポリシーに似ています。

Note

App Service CORS と独自の CORS コードを一緒に使用しないでください。 一緒に使用すると、App Service CORS が優先され、独自の CORS コードは機能しません。

許可された配信元をワイルドカード サブドメインに設定する方法

*.contoso.com のようなワイルドカード サブドメインには、ワイルドカード配信元 * よりも厳しい制限があります。 ただし、Azure portal 内にあるアプリの CORS 管理ページでは、許可された配信元としてワイルドカード サブドメインを設定することができません。 ただし、次のように Azure CLI を使用すれば可能です。

az webapp cors add --resource-group <group-name> --name <app-name> --allowed-origins 'https://*.contoso.com'

ACCESS-CONTROL-ALLOW-CREDENTIALS ヘッダーを応答で有効にする方法

Cookie や認証トークンなどの資格情報をアプリで送信する必要がある場合、ブラウザーは、応答に ACCESS-CONTROL-ALLOW-CREDENTIALS ヘッダーを必要とします。 App Service でこれを有効にするには、properties.cors.supportCredentialstrue に設定します。

az resource update --name web --resource-group <group-name> \
  --namespace Microsoft.Web --resource-type config \
  --parent sites/<app-name> --set properties.cors.supportCredentials=true

この操作は、許可された配信元にワイルドカードの配信元 '*' が含まれている場合は許可されません。 AllowAnyOriginAllowCredentials を指定する構成は安全ではなく、クロスサイト リクエスト フォージェリが発生する可能性があります。 資格情報を許可するには、ワイルドカードの配信元をワイルドカード サブドメインに置き換えてみてください。

リソースをクリーンアップする

前の手順では、リソース グループ内に Azure リソースを作成しました。 これらのリソースが将来必要になると想定していない場合、Cloud Shell で次のコマンドを実行して、リソース グループを削除します。

az group delete --name myResourceGroup

このコマンドの実行には、少し時間がかかる場合があります。

次のステップ

ここで学習した内容は次のとおりです。

  • Azure CLI を使用して App Service リソースを作成する
  • Git を使用して RESTful API を Azure にデプロイする
  • App Service の CORS サポートを有効にする

次のチュートリアルに進み、ユーザーを認証および承認する方法を学習してください。