---
lang: ja-jp
breaks: true
---
# 参考資料
> cURL で ASP.NET Core の Web API を呼び出す
> https://learn.microsoft.com/ja-jp/azure/active-directory/develop/howto-call-a-web-api-with-curl?tabs=dotnet6&pivots=no-api
> ms-identity-docs-code-dotnet/web-api/
> https://github.com/Azure-Samples/ms-identity-docs-code-dotnet/tree/main/web-api

## 前提条件
* アクティブなサブスクリプションを持つAzureアカウント。
* ※無料アカウントでも可能。
*
## Microsoft ID プラットフォームへのアプリケーションの登録
### WebAPI の登録

* `Azure Active Directory` に WebAPI をアプリとして登録する。
* 
* 
* 
* リダイレクト URIは空のままで良い。
* 
* 「ディレクトリ (テナント) ID」「アプリケーション (クライアント) ID」 を控えておく。
* 
*
#### API を公開する
* WebAPIに外部に公開するスコープを定義することで、アクセス権限を設定する。
* ※ クライアントアプリケーションがリクエストと同時に渡す `アクセス トークン` が有効な場合にのみ要求に応じるように構成する。
* 
* 
* 
* 特に変更せずに「保存してから続ける」をクリックする。
* 
* 
* 
* 
* 
* 
* 
* 
* 
### アクセストークンを受け取る Webアプリ の登録
* `アクセストークン` を受け取る為のWebアプリの作成が別途必要。
* 
* `Azure Active Directory` に Webアプリ をアプリとして登録する。
* 
* 
* 
* 作成した Webアプリ が受け取る `リダイレクトURI` を設定する。
* 
* 「Web」を選択する。
* 開発及びテストの際は、`http://localhost` でも可能。
* ただし、`/authorize` エンドポイントにGETする際の、`redirect_uri`パラメータと必ず一致する必要がある。一致しない場合はエラーとなる。
* 
*
#### クライアント シークレットの追加
* アプリが自分自身を識別する為に使用する `クライアントシークレット` (※`アプリケーションパスワード`)を構成します。
* Webアプリが `アクセストークン` を要求する際に `クライアントシークレット` が必要になる。
* クライアント シークレットを追加する
* 
* 
* 
* 
* 
* 
* `クライアントシークレット`には 有効期限があり、二度と表示されない為登録時に控えておく必要がある。
#### アプリケーション権限を追加して WebAPI へのアクセスを許可する
* `アクセストークン` を受け取る Webアプリ に WebAPI へのアクセススコープを指定することで、Microsoft ID platform が提供するスコープを含む`アクセストークン` を受け取ることが出来るようになる。
* 
* 
* 
* 
* 
* 「委任されたアクセス許可」を選択する。
* 
* アクセス許可にチェックを入れる
* 
* 
* 
* 
* 
* 
*
## WebAPI をテストする
### 承認コードを要求する
* クライアントアプリケーションがユーザを `/authorize` エンドポイントに誘導する。
* `/authorize` エンドポイントからのレスポンスはHTML及びJavaScriptとなる為、必ずWebブラウザを使用する必要がある。
* リクエストに必要な情報
* WebアプリのテナントID
* WebアプリのクライアントID
* WebAPIのクライアントID
* ブラウザが アクセストークンを受け取る Webアプリ にリダイレクトされる。
* 取得される情報
* 認可コード:`?code={authorization_code}`
### 承認コード を使用して アクセス トークン を取得する
* `/oauth2/v2.0/token` エンドポイントにアクセスし、`アクセストークン` を取得する。
* 必要なパラメータ
* WebアプリのテナントID
* WebアプリのクライアントID
* WebAPIクライアントID
* 認可コード
* クライアントシークレット
*
### アクセス トークンを使用して WebAPI を呼び出す
* HTTPリクエストヘッダに `"Authorization: Bearer {access_token}"` を追加して WebAPIを呼び出す。
*
## アクセストークンを取得するWebアプリ
### テンプレートからプロジェクトを作成


### アクセストークンの取得を要求するページを追加する
* 
* 
* 
*
#### MsIdAccessTokenRequest.cshtml
```csharp=
@page
@model ToReceiveAccessToken.Pages.MsIdAccessTokenRequestModel
@{
ViewData["Title"] = "Microsoft ID プラットフォーム アクセストークン取得要求";
}
<h1>@ViewData["Title"]</h1>
<p>このページは、Microsoft ID プラットフォーム のアクセストークンの取得要求を行います。</p>
<form method="post">
<input type="submit" class="btn btn-primary" asp-page-handler="MsIdAccessTokenRequest" value="アクセストークン取得要求" />
</form>
<p>@Model.Output</p>
<p>@Model.RequestUrl</p>
```
#### MsIdAccessTokenRequest.cshtml.cs
```csharp=
public class MsIdAccessTokenRequestModel : PageModel
{
public string Output { get; set; }
public string RequestUrl { get; set; }
public MsIdAccessTokenRequestModel()
: base()
{
Output = "";
RequestUrl = "";
}
public async Task<IActionResult> OnPostMsIdAccessTokenRequest()
{
string url = await RequestAuthorizationCode(base.Request);
Output = $"アクセストークンの要求を行いました。";
RequestUrl = url;
return Redirect(url);
//return Page();
}
private async Task<string> RequestAuthorizationCode(
HttpRequest request
)
{
string tenant_id = "テナントID";
string web_app_calls_web_api_application_client_id = "WebアプリのクライアントID";
string redirect_uri = $"http{(request.IsHttps?"s":"")}://{request.Host}/MsIdRedirect";
string web_API_application_client_id = "WebAPIのクライアントID";
string scope = "API.GETPOST";
string url = $"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize?client_id={web_app_calls_web_api_application_client_id}&response_type=code&redirect_uri={redirect_uri}&response_mode=query&scope=api://{web_API_application_client_id}/{scope}";
return url;
}
}
```
### リダイレクトを受け付けて、アクセストークンを取得するページを追加する
* 
* 
* 
#### MsIdRedirect.cshtml
```csharp=
@page
@model ToReceiveAccessToken.Pages.MsIdRedirectModel
@{
ViewData["Title"] = "Microsoft ID プラットフォーム のリダイレクトページ";
}
<h1>@ViewData["Title"]</h1>
<p>このページは、Microsoft ID プラットフォーム のリダイレクトページです。</p>
@if (string.IsNullOrEmpty(Model.AuthorizationCode) == false)
{
<p>@Model.Output</p>
<form method="post">
<input type="submit" class="btn btn-primary" asp-page-handler="MsIdAccessTokenRequest" value="アクセストークン取得" />
<input type="hidden" id="AuthorizationCode" name="AuthorizationCode" asp-for="AuthorizationCode" />
</form>
}
```
#### MsIdRedirect.cshtml.cs
```cshap=
public class MsIdRedirectModel : PageModel
{
public string Output { get; set; } = "";
[BindProperty]
public string AuthorizationCode { get; set; } = "";
private static HttpClient? _httpClient;
public Dictionary<string, object?>? ResponseJson = null;
public async Task OnGet()
{
foreach (var getQuery in base.Request.Query)
{
Debug.WriteLine($"{getQuery.Key}:{getQuery.Value}");
}
base.Request.Query.TryGetValue("code", out Microsoft.Extensions.Primitives.StringValues code);
// `session_state` は必要ない。
base.Request.Query.TryGetValue("session_state", out Microsoft.Extensions.Primitives.StringValues session_state);
AuthorizationCode = code.ToString();
Output = $"認証コード=[{code}]";
}
public async Task<IActionResult> OnPostMsIdAccessTokenRequest()
{
Output = "";
if (string.IsNullOrEmpty(AuthorizationCode) == false)
{
try
{
Dictionary<string, object?>? responseJson =
await RequestAuthorizationCode(base.Request, AuthorizationCode);
Output = $"アクセストークンが取得されました。";
ResponseJson = responseJson;
}
catch (Exception ex)
{
Output = $"アクセストークンの取得に失敗しました。{ex.Message}";
}
}
return Page();
}
private async Task<Dictionary<string, object?>?> RequestAuthorizationCode(
HttpRequest request,
string authorization_code
)
{
string tenant_id = "テナントID";
string web_app_calls_web_api_application_client_id = "WebアプリのクライアントID";
string redirect_uri = $"http{(request.IsHttps ? "s" : "")}://{request.Host}/MsIdRedirect";
string web_API_application_client_id = "WebAPIのクライアントID";
string scope = "API.GETPOST";
string client_secret = "Webアプリのクライアントシークレット";
string url = $"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token";
string client_id = $"{web_app_calls_web_api_application_client_id}";
string api = $"api://{web_API_application_client_id}/{scope}";
// `session_state` があるとエラーになる。
//string code = $"{authorization_code}&session_state={web_app_calls_web_api_application_client_id}";
string code = $"{authorization_code}";
string grant_type = "authorization_code";
if (_httpClient == null)
{
_httpClient = new HttpClient();
}
var parameters = new Dictionary<string, string>()
{
{ "client_id", client_id },
{ "api", api }, // "api"は、"" でも動作した。
{ "code", code },
{ "redirect_uri", redirect_uri },
{ "grant_type", grant_type },
{ "client_secret", client_secret },
};
var content = new FormUrlEncodedContent(parameters);
HttpResponseMessage response = await _httpClient.PostAsync(url, content)
.ConfigureAwait(false);
Debug.WriteLine("-----------------------------------------");
Debug.WriteLine(response.Content.Headers.ContentType?.ToString());
Debug.WriteLine(response.Content.Headers.ContentType?.MediaType);
Debug.WriteLine(response.Content.Headers.ContentType?.CharSet);
Debug.WriteLine("-----------------------------------------");
foreach (var header in response.Headers)
{
string value = string.Join(",", header.Value);
Debug.WriteLine($"{header.Key}: {value}");
}
Debug.WriteLine("-----------------------------------------");
string responseContent = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
Dictionary<string, object?>? responseJson = null;
if (string.IsNullOrEmpty(responseContent) == false)
{
Debug.WriteLine(responseContent);
responseJson = await response.Content.ReadFromJsonAsync<Dictionary<string, object?>>()
.ConfigureAwait(false);
if (responseJson != null)
{
foreach (var pair in responseJson)
{
Debug.WriteLine($"[{pair.Key}:{pair.Value}]");
}
}
}
if (response.IsSuccessStatusCode == false)
{
throw new Exception("アクセストークンの要求に失敗しました。");
}
return responseJson;
}
}
```
### ナビゲーションメニューに追加する
_Layout.cshtml
```htmlembedded=
・・・
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
・・・
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/MsIdAccessTokenRequest">Microsoft ID アクセストークン要求</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/MsIdRedirect">Microsoft ID リダイレクト</a>
</li>
</ul>
</div>
・・・
```
### 実行してみる





## アクセストークンを使用してWebAPIを呼び出すアプリ