クライアント アプリケーション オブジェクトは構築済みです。 次はこれを使用して Web API を呼び出すトークンを取得します。 ASP.NET または ASP.NET Core では、Web API の呼び出しはコントローラーで実行されます。
Microsoft.Identity.Web には、Microsoft Graph またはダウンストリーム Web API を呼び出す便利なサービスを提供する拡張メソッドが追加されています。 これらのメソッドの詳細については、「Web API を呼び出す Web アプリ: API を呼び出す」を参照してください。 これらのヘルパー メソッドを使用すれば、トークンを手動で取得する必要はありません。
ただし、トークンを手動で取得する場合は、ホーム コントローラーで取得することを目的とした Microsoft.Identity.Web の使用の例が、次のコードによって示されています。 これにより、REST API (Microsoft Graph SDK ではなく) を使用した、Microsoft Graph の呼び出しが行われます。 通常、トークンを取得する必要はありませんが、要求に追加する Authorization ヘッダーを作成する必要があります。 Authorization ヘッダーを取得するには、コントローラーのコンストラクター (Blazor を使用する場合はページ コンストラクター) 内での依存関係の挿入によって、IAuthorizationHeaderProvider
サービスを挿入し、それをコントローラー アクションで使用します。 このインターフェイスには、プロトコル (Bearer や Pop など) とトークンを含む文字列を生成するメソッドが用意されています。 ユーザーに代わって API を呼び出す Authorization ヘッダーを取得するには、(CreateAuthorizationHeaderForUserAsync
) を使用します。 アプリケーション自体に代わってダウンストリーム API を呼び出す Authorization ヘッダーを取得するには、デーモン シナリオで (CreateAuthorizationHeaderForAppAsync
) を使用します。
コントローラー メソッドは、認証されたユーザーのみが Web アプリを使用できるようにする [Authorize]
属性によって保護されます。
[Authorize]
public class HomeController : Controller
{
readonly IAuthorizationHeaderProvider authorizationHeaderProvider;
public HomeController(IAuthorizationHeaderProvider authorizationHeaderProvider)
{
this.authorizationHeaderProvider = authorizationHeaderProvider;
}
// Code for the controller actions (see code below)
}
ASP.NET Coreは、依存関係の挿入によって IAuthorizationHeaderProvider
を使用できるようにします。
Microsoft Graph を呼び出すトークンを取得する HomeController
のアクションの簡略化されたコードを次に示します。
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Acquire the access token.
string[] scopes = new string[]{"user.read"};
string accessToken = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(scopes);
// Use the access token to call a protected web API.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", accessToken);
string json = await client.GetStringAsync(url);
}
このシナリオに必要なコードをさらに理解したい場合は、ms-identity-aspnetcore-Webapp-tutorial チュートリアルのフェーズ 2 (2-1-Web App Calls Microsoft Graph) の手順を参照してください。
コントローラー アクションの上 (または Razor テンプレートを使用する場合は Razor ページ) の AuthorizeForScopes
属性は、Microsoft.Identity.Web によって提供されます。 これにより、必要に応じて、かつ段階的にユーザーに同意が求められます。
次のような複雑なバリエーションもあります。
- 複数の API の呼び出し。
- 増分同意と条件付きアクセスの処理。
このような高度な手順については、3-WebApp-multi-APIs チュートリアルの第 3 章を参照してください。
ASP.NET のコードは、ASP.NET Core 用に示したコードと似ています。
[Authorize]
属性によって保護されたコントローラー アクションは、コントローラーの ClaimsPrincipal
メンバーのテナント ID とユーザー ID を抽出します (ASP.NET は HttpContext.User
を使用)。 これにより、認証されたユーザーのみがアプリを使用できるようになります。
Microsoft.Identity.Web は、Microsoft Graph やダウンストリーム Web API を呼び出したり、Authorization ヘッダーやトークンを取得したりするための便利なサービスを提供する拡張メソッドをコントローラーに追加します。 API を直接呼び出すのに使用されるメソッドの詳細については、「Web API を呼び出す Web アプリ: API を呼び出す」を参照してください。 これらのヘルパー メソッドを使用すれば、トークンを手動で取得する必要はありません。
ただし、トークンの取得または Authorization ヘッダーの構築を手動で行いたい場合は、Microsoft.Identity.Web を使用してコントローラーでそれを行う方法を示す次のコードを参照してください。 これにより、Microsoft Graph SDK ではなく REST API を使用した、API (Microsoft Graph) の呼び出しが行われます。
Authorization ヘッダーを取得するには、拡張メソッド GetAuthorizationHeaderProvider
を使用してコントローラーから IAuthorizationHeaderProvider
サービスを取得します。 ユーザーに代わって API を呼び出す Authorization ヘッダーを取得するには、CreateAuthorizationHeaderForUserAsync
を使用します。 アプリケーション自体に代わってダウンストリーム API を呼び出す Authorization ヘッダーを取得するには、デーモン シナリオで CreateAuthorizationHeaderForAppAsync
を使用します。
次のスニペットは、HomeController
のアクション (REST API として Microsoft Graph を呼び出す Authorization ヘッダーが取得されます) を示したものです。
[Authorize]
public class HomeController : Controller
{
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Get an authorization header.
IAuthorizationHeaderProvider authorizationHeaderProvider = this.GetAuthorizationHeaderProvider();
string[] scopes = new string[]{"user.read"};
string authorizationHeader = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(scopes);
// Use the access token to call a protected web API.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", authorizationHeader);
string json = await client.GetStringAsync(url);
}
}
次のスニペットは、HomeController
のアクション (REST API として Microsoft Graph を呼び出すアクセス トークンが取得されます) を示したものです。
[Authorize]
public class HomeController : Controller
{
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Get an authorization header.
ITokenAcquirer tokenAcquirer = TokenAcquirerFactory.GetDefaultInstance().GetTokenAcquirer();
string[] scopes = new string[]{"user.read"};
string token = await tokenAcquirer.GetTokenForUserAsync(scopes);
// Use the access token to call a protected web API.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
string json = await client.GetStringAsync(url);
}
}
Java のサンプルでは、API を呼び出すコードは getUsersFromGraph
メソッド (AuthPageController.java#L62) にあります。
メソッドから getAuthResultBySilentFlow
の呼び出しが試行されます。 ユーザーがより多くのスコープに同意する必要がある場合、コードでは MsalInteractionRequiredException
オブジェクトが処理され、ユーザーがチャレンジされます。
@RequestMapping("/msal4jsample/graph/me")
public ModelAndView getUserFromGraph(HttpServletRequest httpRequest, HttpServletResponse response)
throws Throwable {
IAuthenticationResult result;
ModelAndView mav;
try {
result = authHelper.getAuthResultBySilentFlow(httpRequest, response);
} catch (ExecutionException e) {
if (e.getCause() instanceof MsalInteractionRequiredException) {
// If the silent call returns MsalInteractionRequired, redirect to authorization endpoint
// so user can consent to new scopes.
String state = UUID.randomUUID().toString();
String nonce = UUID.randomUUID().toString();
SessionManagementHelper.storeStateAndNonceInSession(httpRequest.getSession(), state, nonce);
String authorizationCodeUrl = authHelper.getAuthorizationCodeUrl(
httpRequest.getParameter("claims"),
"User.Read",
authHelper.getRedirectUriGraph(),
state,
nonce);
return new ModelAndView("redirect:" + authorizationCodeUrl);
} else {
mav = new ModelAndView("error");
mav.addObject("error", e);
return mav;
}
}
if (result == null) {
mav = new ModelAndView("error");
mav.addObject("error", new Exception("AuthenticationResult not found in session."));
} else {
mav = new ModelAndView("auth_page");
setAccountInfo(mav, httpRequest);
try {
mav.addObject("userInfo", getUserInfoFromGraph(result.accessToken()));
return mav;
} catch (Exception e) {
mav = new ModelAndView("error");
mav.addObject("error", e);
}
}
return mav;
}
// Code omitted here
この Node.js サンプルでは、トークンを取得するコードは AuthProvider
クラスの acquireToken
メソッドにあります。
acquireToken(options = {}) {
return async (req, res, next) => {
try {
const msalInstance = this.getMsalInstance(this.msalConfig);
/**
* If a token cache exists in the session, deserialize it and set it as the
* cache for the new MSAL CCA instance. For more, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/caching.md
*/
if (req.session.tokenCache) {
msalInstance.getTokenCache().deserialize(req.session.tokenCache);
}
const tokenResponse = await msalInstance.acquireTokenSilent({
account: req.session.account,
scopes: options.scopes || [],
});
/**
* On successful token acquisition, write the updated token
* cache back to the session. For more, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/caching.md
*/
req.session.tokenCache = msalInstance.getTokenCache().serialize();
req.session.accessToken = tokenResponse.accessToken;
req.session.idToken = tokenResponse.idToken;
req.session.account = tokenResponse.account;
res.redirect(options.successRedirect);
} catch (error) {
if (error instanceof msal.InteractionRequiredAuthError) {
return this.login({
scopes: options.scopes || [],
redirectUri: options.redirectUri,
successRedirect: options.successRedirect || '/',
})(req, res, next);
}
next(error);
}
};
}
このアクセス トークンは、/profile
エンドポイントへの要求を処理するために使用されます。
router.get('/profile',
isAuthenticated, // check if user is authenticated
async function (req, res, next) {
try {
const graphResponse = await fetch(GRAPH_ME_ENDPOINT, req.session.accessToken);
res.render('profile', { profile: graphResponse });
} catch (error) {
next(error);
}
}
);
Python のサンプルでは、API を呼び出すコードは app.py にあります。
このコードでは、トークン キャッシュからのトークンの取得が試行されます。 トークンを取得できない場合、ユーザーはサインイン ルートにリダイレクトされます。 それ以外の場合は、API の呼び出しに進むことができます。
@app.route("/call_downstream_api")
def call_downstream_api():
token = auth.get_token_for_user(app_config.SCOPE)
if "error" in token:
return redirect(url_for("login"))
# Use access token to call downstream api
api_result = requests.get(
app_config.ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']},
timeout=30,
).json()
return render_template('display.html', result=api_result)