U hebt uw clienttoepassingsobject gebouwd. Nu gebruikt u het om een token te verkrijgen om een web-API aan te roepen. In ASP.NET of ASP.NET Core wordt een web-API aangeroepen in de controller:
Microsoft.Identity.Web voegt uitbreidingsmethoden toe die handige services bieden voor het aanroepen van Microsoft Graph of een downstream-web-API. Deze methoden worden uitgebreid beschreven in een web-app die web-API's aanroept: een API aanroepen. Met deze helpermethoden hoeft u geen token handmatig te verkrijgen.
Als u echter handmatig een token wilt verkrijgen, ziet u in de volgende code een voorbeeld van het gebruik van Microsoft.Identity.Web in een homecontroller. Microsoft Graph wordt aangeroepen met behulp van de REST API (in plaats van de Microsoft Graph SDK). Meestal hoeft u geen token op te halen. U moet een autorisatieheader maken die u aan uw aanvraag toevoegt. Als u een autorisatieheader wilt ophalen, injecteert u de IAuthorizationHeaderProvider
service door afhankelijkheidsinjectie in de constructor van uw controller (of de paginaconstructor als u Blazor gebruikt) en gebruikt u deze in de controlleracties. Deze interface bevat methoden die een tekenreeks produceren die het protocol bevat (Bearer, Pop, ...) en een token. Als u een autorisatieheader wilt ophalen om namens de gebruiker een API aan te roepen, gebruikt u (CreateAuthorizationHeaderForUserAsync
). Als u een autorisatieheader wilt ophalen om een downstream-API namens de toepassing zelf aan te roepen, gebruikt u (CreateAuthorizationHeaderForAppAsync
in een daemon-scenario).
De controllermethoden worden beveiligd door een [Authorize]
kenmerk dat ervoor zorgt dat alleen geverifieerde gebruikers de web-app kunnen gebruiken.
[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 maakt IAuthorizationHeaderProvider
beschikbaar via afhankelijkheidsinjectie.
Hier volgt vereenvoudigde code voor de actie van de HomeController
, waarmee een token wordt opgehaald om Microsoft Graph aan te roepen:
[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);
}
Zie de stap fase 2 (2-1-Web-app Roept Microsoft Graph) van de zelfstudie ms-identity-aspnetcore-webapp-tutorial voor meer inzicht in de code die vereist is voor dit scenario.
Het AuthorizeForScopes
kenmerk boven op de controlleractie (of van de Razor-pagina als u een Razor-sjabloon gebruikt) wordt geleverd door Microsoft.Identity.Web. Het zorgt ervoor dat de gebruiker indien nodig om toestemming wordt gevraagd en incrementeel.
Er zijn andere complexe variaties, zoals:
- Verschillende API's aanroepen.
- Incrementele toestemming en voorwaardelijke toegang verwerken.
Deze geavanceerde stappen worden behandeld in hoofdstuk 3 van de zelfstudie 3-WebApp-multi-API's .
De code voor ASP.NET is vergelijkbaar met de code die wordt weergegeven voor ASP.NET Core:
- Een controlleractie, beveiligd door een
[Authorize]
kenmerk, extraheert de tenant-id en gebruikers-id van het ClaimsPrincipal
lid van de controller (ASP.NET gebruikt HttpContext.User
). Dit zorgt ervoor dat alleen geverifieerde gebruikers de app kunnen gebruiken.
Microsoft.Identity.Web voegt uitbreidingsmethoden toe aan de controller die handige services biedt om Microsoft Graph of een downstream-web-API aan te roepen, of om een autorisatieheader of zelfs een token op te halen. De methoden die worden gebruikt om een API rechtstreeks aan te roepen, worden in detail uitgelegd in een web-app die web-API's aanroept: een API aanroepen. Met deze helpermethoden hoeft u geen token handmatig te verkrijgen.
Als u echter handmatig een token wilt verkrijgen of een autorisatieheader wilt maken, ziet u in de volgende code hoe u Microsoft.Identity.Web gebruikt om dit in een controller te doen. Er wordt een API (Microsoft Graph) aangeroepen met behulp van de REST API in plaats van de Microsoft Graph SDK.
Als u een autorisatieheader wilt ophalen, krijgt u een IAuthorizationHeaderProvider
service van de controller met behulp van een extensiemethode GetAuthorizationHeaderProvider
. Als u een autorisatieheader wilt ophalen om namens de gebruiker een API aan te roepen, gebruikt u CreateAuthorizationHeaderForUserAsync
. Als u een autorisatieheader wilt ophalen om een downstream-API namens de toepassing zelf aan te roepen, gebruikt CreateAuthorizationHeaderForAppAsync
u dit in een daemon-scenario.
Het volgende codefragment toont de actie van de HomeController
, waarmee een autorisatieheader wordt opgehaald om Microsoft Graph aan te roepen als een REST API:
[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);
}
}
Het volgende codefragment toont de actie van het HomeController
, waarmee een toegangstoken wordt opgehaald om Microsoft Graph aan te roepen als een REST API:
[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);
}
}
In het Java-voorbeeld bevindt de code die een API aanroept zich in de getUsersFromGraph
methode in AuthPageController.java#L62.
De methode probeert aan te roepen getAuthResultBySilentFlow
. Als de gebruiker toestemming moet geven voor meer bereiken, verwerkt de code het MsalInteractionRequiredException
object om de gebruiker uit te dagen.
@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
In het Node.js voorbeeld bevindt de code die een token verkrijgt zich in de acquireToken
methode van de AuthProvider
klasse.
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);
}
};
}
Dit toegangstoken wordt vervolgens gebruikt om aanvragen naar het /profile
eindpunt te verwerken:
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);
}
}
);
In het Python-voorbeeld bevindt de code die de API aanroept zich in app.py.
De code probeert een token op te halen uit de tokencache. Als er geen token kan worden opgehaald, wordt de gebruiker omgeleid naar de aanmeldingsroute. Anders kan de API worden aangeroepen.
@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)