Utworzono obiekt aplikacji klienckiej. Teraz użyjesz go do uzyskania tokenu w celu wywołania internetowego interfejsu API. W ASP.NET lub ASP.NET Core wywoływanie internetowego interfejsu API odbywa się w kontrolerze:
Microsoft.Identity.Web dodaje metody rozszerzenia, które zapewniają wygodne usługi do wywoływania programu Microsoft Graph lub podrzędnego internetowego interfejsu API. Te metody zostały szczegółowo wyjaśnione w aplikacji internetowej, która wywołuje internetowe interfejsy API: wywoływanie interfejsu API. W przypadku tych metod pomocnika nie trzeba ręcznie uzyskiwać tokenu.
Jeśli jednak chcesz ręcznie uzyskać token, poniższy kod przedstawia przykład użycia pliku Microsoft.Identity.Web do tego w kontrolerze macierzystym. Wywołuje program Microsoft Graph przy użyciu interfejsu API REST (zamiast zestawu Microsoft Graph SDK). Zazwyczaj nie musisz pobierać tokenu, musisz utworzyć nagłówek autoryzacji dodany do żądania. Aby uzyskać nagłówek autoryzacji, należy wstrzyknąć usługę IAuthorizationHeaderProvider
przez wstrzykiwanie zależności w konstruktorze kontrolera (lub konstruktorze strony, jeśli używasz platformy Blazor) i używać jej w akcjach kontrolera. Ten interfejs zawiera metody, które tworzą ciąg zawierający protokół (Bearer, Pop, ...) i token. Aby uzyskać nagłówek autoryzacji w celu wywołania interfejsu API w imieniu użytkownika, użyj (CreateAuthorizationHeaderForUserAsync
). Aby uzyskać nagłówek autoryzacji w celu wywołania podrzędnego interfejsu API w imieniu samej aplikacji, w scenariuszu demona użyj (CreateAuthorizationHeaderForAppAsync
).
Metody kontrolera są chronione przez [Authorize]
atrybut, który gwarantuje, że tylko uwierzytelnieni użytkownicy mogą używać aplikacji internetowej.
[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 udostępnia IAuthorizationHeaderProvider
przez wstrzykiwanie zależności.
Oto uproszczony kod akcji HomeController
programu , który pobiera token do wywołania programu Microsoft Graph:
[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);
}
Aby lepiej zrozumieć kod wymagany w tym scenariuszu, zobacz krok krok 2 (2-1-Web app Calls Microsoft Graph) w samouczku ms-identity-aspnetcore-webapp-tutorial .
Atrybut AuthorizeForScopes
na górze akcji kontrolera (lub strony Razor, jeśli używasz szablonu Razor) jest udostępniany przez Microsoft.Identity.Web. Gwarantuje to, że użytkownik zostanie poproszony o zgodę w razie potrzeby i przyrostowo.
Istnieją inne złożone odmiany, takie jak:
- Wywoływanie kilku interfejsów API.
- Przetwarzanie zgody przyrostowej i dostępu warunkowego.
Te zaawansowane kroki zostały omówione w rozdziale 3 samouczka 3-WebApp-multi-APIs .
Kod ASP.NET jest podobny do kodu pokazanego dla ASP.NET Core:
- Akcja kontrolera, chroniona
[Authorize]
przez atrybut, wyodrębnia identyfikator dzierżawy i identyfikator ClaimsPrincipal
użytkownika członka kontrolera (ASP.NET używa HttpContext.User
). Dzięki temu tylko uwierzytelnieni użytkownicy mogą korzystać z aplikacji.
Microsoft.Identity.Web dodaje metody rozszerzenia do kontrolera, które zapewniają usługi wygodne do wywoływania programu Microsoft Graph lub podrzędnego internetowego interfejsu API, lub uzyskiwania nagłówka autoryzacji, a nawet tokenu. Metody używane do bezpośredniego wywoływania interfejsu API zostały szczegółowo wyjaśnione w artykule Aplikacja internetowa, która wywołuje internetowe interfejsy API: Wywoływanie interfejsu API. W przypadku tych metod pomocnika nie trzeba ręcznie uzyskiwać tokenu.
Jeśli jednak chcesz ręcznie uzyskać token lub skompilować nagłówek autoryzacji, poniższy kod pokazuje, jak używać microsoft.Identity.Web, aby to zrobić w kontrolerze. Wywołuje interfejs API (Microsoft Graph) przy użyciu interfejsu API REST zamiast zestawu Microsoft Graph SDK.
Aby uzyskać nagłówek autoryzacji, należy pobrać usługę IAuthorizationHeaderProvider
z kontrolera przy użyciu metody GetAuthorizationHeaderProvider
rozszerzenia . Aby uzyskać nagłówek autoryzacji w celu wywołania interfejsu API w imieniu użytkownika, użyj polecenia CreateAuthorizationHeaderForUserAsync
. Aby uzyskać nagłówek autoryzacji w celu wywołania podrzędnego interfejsu API w imieniu samej aplikacji, w scenariuszu demona użyj polecenia CreateAuthorizationHeaderForAppAsync
.
Poniższy fragment kodu przedstawia akcję HomeController
elementu , która pobiera nagłówek autoryzacji w celu wywołania programu Microsoft Graph jako interfejsu API REST:
[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);
}
}
Poniższy fragment kodu przedstawia akcję HomeController
elementu , która pobiera token dostępu w celu wywołania programu Microsoft Graph jako interfejsu API REST:
[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);
}
}
W przykładzie języka Java kod wywołujący interfejs API znajduje się w getUsersFromGraph
metodzie w pliku AuthPageController.java#L62.
Metoda próbuje wywołać getAuthResultBySilentFlow
metodę . Jeśli użytkownik musi wyrazić zgodę na więcej zakresów, kod przetwarza MsalInteractionRequiredException
obiekt w celu zakwestionowania użytkownika.
@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
W przykładzie Node.js kod, który uzyskuje token, jest w acquireToken
metodzie AuthProvider
klasy .
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);
}
};
}
Ten token dostępu jest następnie używany do obsługi żądań do punktu końcowego /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);
}
}
);
W przykładzie języka Python kod wywołujący interfejs API znajduje się w app.py.
Kod próbuje uzyskać token z pamięci podręcznej tokenu. Jeśli nie może uzyskać tokenu, przekierowuje użytkownika do trasy logowania. W przeciwnym razie może przejść do wywołania interfejsu 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)