Downstream-API's aanroepen vanuit web-apps

In deze handleiding wordt uitgelegd hoe u downstream-API's aanroept vanuit ASP.NET Core- en OWIN-webtoepassingen met behulp van Microsoft. Identity.Web. In web-apps verkrijgt u tokens namens de aangemelde gebruiker om API's aan te roepen met gedelegeerde machtigingen.

Inzicht in de tokenstroom

Wanneer een gebruiker zich aanmeldt bij uw webtoepassing, kunt u downstream-API's (Microsoft Graph, Azure services of aangepaste API's) namens hen aanroepen. Microsoft. Identity.Web verwerkt tokenverwerving, caching en automatisch vernieuwen.

De gebruikerstokenstroom controleren

sequenceDiagram
    participant User as User Browser
    participant WebApp as Your Web App
    participant AzureAD as Microsoft Entra ID
    participant API as Downstream API

    User->>WebApp: 1. Access page requiring API data
    Note over WebApp: User already signed in
    WebApp->>AzureAD: 2. Request access token for API<br/>(using user's refresh token)
    AzureAD->>AzureAD: 3. Validate & check consent
    AzureAD->>WebApp: 4. Return access token
    Note over WebApp: Cache token
    WebApp->>API: 5. Call API with token
    API->>WebApp: 6. Return data
    WebApp->>User: 7. Render page with data

Vereisten bekijken

Controleer of uw omgeving voldoet aan de volgende vereisten voordat u begint.

  • Web-app geconfigureerd met OpenID Connect-verificatie
  • Aanmelden van gebruiker werkt
  • App-registratie met API-machtigingen geconfigureerd
  • Gebruikerstoestemming verkregen (of beheerderstoestemming verleend)

ASP.NET Core implementeren

1. Verificatie inrichten en tokens ophalen

Voeg authenticatieservices toe en schakel in uw Program.cs bestand het verkrijgen van tokens in.

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add authentication with explicit scheme
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.Run();

2. Configureer appsettings.json

Definieer uw Microsoft Entra ID-app-registratie- en downstream-API-instellingen in appsettings.json.

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath": "/signout-callback-oidc",
    "ClientCredentials": [
      {
        "SourceType": "ClientSecret",
        "ClientSecret": "your-client-secret"
      }
    ]
  },
  "DownstreamApis": {
    "GraphAPI": {
      "BaseUrl": "https://graph.microsoft.com/v1.0",
      "Scopes": ["user.read", "mail.read"]
    },
    "MyAPI": {
      "BaseUrl": "https://myapi.example.com",
      "Scopes": ["api://my-api-id/access_as_user"]
    }
  }
}

Belangrijk: Voor web-apps die downstream-API's aanroepen, hebt u clientreferenties (certificaat of geheim) nodig naast de aanmeldingsconfiguratie.

3. Ondersteuning voor downstream-API toevoegen

Kies een van de volgende opties om uw downstream-API's te registreren.

Optie A: Benoemde API's registreren

Met de volgende code worden meerdere downstream-API's van de configuratie geregistreerd.

using Microsoft.Identity.Web;

// Register multiple downstream APIs
builder.Services.AddDownstreamApis(
    builder.Configuration.GetSection("DownstreamApis"));

Option B: Gebruik Microsoft Graph Helper

Met de volgende code wordt de Microsoft Graph SDK-client geregistreerd bij de configuratie.

// Install: Microsoft.Identity.Web.GraphServiceClient
builder.Services.AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApis:GraphAPI"));

4. Downstream-API aanroepen vanaf controller

Injecteer IDownstreamApi in uw controller en roep de API aan namens de aangemelde gebruiker.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;
using Microsoft.Identity.Abstractions;

[Authorize]
public class ProfileController : Controller
{
    private readonly IDownstreamApi _downstreamApi;
    private readonly ILogger<ProfileController> _logger;

    public ProfileController(
        IDownstreamApi downstreamApi,
        ILogger<ProfileController> logger)
    {
        _downstreamApi = downstreamApi;
        _logger = logger;
    }

    public async Task<IActionResult> Index()
    {
        try
        {
            // Call downstream API on behalf of user
            var userData = await _downstreamApi.GetForUserAsync<UserData>(
                "MyAPI",
                options => options.RelativePath = "api/profile");

            return View(userData);
        }
        catch (MicrosoftIdentityWebChallengeUserException ex)
        {
            // Incremental consent required
            // Redirect user to consent page
            return Challenge(
                new AuthenticationProperties
                {
                    RedirectUri = "/Profile"
                },
                OpenIdConnectDefaults.AuthenticationScheme);
        }
        catch (HttpRequestException ex)
        {
            _logger.LogError(ex, "Failed to call downstream API");
            return View("Error");
        }
    }
}

5. Downstream-API aanroepen vanaf Razor Page

Injecteer IDownstreamApi in uw Razor Page-model en roep de API aan.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Identity.Web;
using Microsoft.Identity.Abstractions;

[Authorize]
public class ProfileModel : PageModel
{
    private readonly IDownstreamApi _downstreamApi;

    public UserData UserData { get; set; }

    public ProfileModel(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    public async Task OnGetAsync()
    {
        try
        {
            UserData = await _downstreamApi.GetForUserAsync<UserData>(
                "MyAPI",
                options => options.RelativePath = "api/profile");
        }
        catch (MicrosoftIdentityWebChallengeUserException)
        {
            // Handle incremental consent
            // User will be redirected to consent page
            throw;
        }
    }
}

Microsoft Graph aanroepen

Gebruik voor oproepen van de Microsoft Graph-API de toegewezen GraphServiceClient.

Pakketten installeren

Installeer het Microsoft Graph-pakket voor Microsoft. Identity.Web.

dotnet add package Microsoft.Identity.Web.GraphServiceClient

Configureer de Graph-client in uw opstartcode.

// Startup configuration
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddMicrosoftGraph(options =>
    {
        options.Scopes = "user.read mail.read";
    })
    .AddInMemoryTokenCaches();

De Graph API aanroepen

Injecteer GraphServiceClient in de controller om Microsoft Graph eindpunten aan te roepen.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph;

[Authorize]
{
    private readonly GraphServiceClient _graphClient;

    public HomeController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }

    public async Task<IActionResult> Index()
    {
        // Get current user's profile
        var user = await _graphClient.Me.GetAsync();

        // Get user's emails
        var messages = await _graphClient.Me.Messages
            .GetAsync(config => config.QueryParameters.Top = 10);

        return View(new { User = user, Messages = messages });
    }
}

Meer informatie over Microsoft Graph integratie


Azure SDK-clients aanroepen

Gebruik MicrosoftIdentityTokenCredential voor het aanroepen van Azure-services.

Pakketten installeren

Installeer de vereiste Azure SDK pakketten.

dotnet add package Microsoft.Identity.Web.Azure
dotnet add package Azure.Storage.Blobs

Registreer de Microsoft Entra tokenreferentie in uw opstartcode.

using Microsoft.Identity.Web;

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

// Add Azure token credential
builder.Services.AddMicrosoftIdentityAzureTokenCredential();

Toegang tot Azure-services

Injecteer de tokenreferentie en gebruik deze met Azure SDK clients.

using Azure.Storage.Blobs;
using Microsoft.Identity.Web;

public class StorageController : Controller
{
    private readonly MicrosoftIdentityTokenCredential _credential;

    public StorageController(MicrosoftIdentityTokenCredential credential)
    {
        _credential = credential;
    }

    [Authorize]
    public async Task<IActionResult> ListBlobs()
    {
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            _credential);

        var container = blobClient.GetBlobContainerClient("mycontainer");
        var blobs = new List<string>();

        await foreach (var blob in container.GetBlobsAsync())
        {
            blobs.Add(blob.Name);
        }

        return View(blobs);
    }
}

Meer informatie over Azure SDK integratie


Aangepaste API's aanroepen met IDownstreamApi

Voor uw eigen REST API's IDownstreamApi biedt u een eenvoudige, configuratiegestuurde benadering.

De API configureren

Definieer de downstream-API-instellingen in appsettings.json.

{
  "DownstreamApis": {
    "MyAPI": {
      "BaseUrl": "https://myapi.example.com",
      "Scopes": ["api://my-api-id/access_as_user"],
      "RequestAppToken": false
    }
  }
}

GET-aanvragen verzenden

Gegevens ophalen uit de downstream-API met optionele queryparameters.

// Simple GET
var data = await _downstreamApi.GetForUserAsync<MyData>(
    "MyAPI",
    options => options.RelativePath = "api/resource");

// GET with query parameters
var results = await _downstreamApi.GetForUserAsync<SearchResults>(
    "MyAPI",
    options =>
    {
        options.RelativePath = "api/search";
        options.QueryParameters = new Dictionary<string, string>
        {
            ["query"] = "test",
            ["limit"] = "10"
        };
    });

POST-aanvragen verzenden

Maak een nieuwe resource in de downstream-API door een aanvraagbody te plaatsen.

var newItem = new CreateItemRequest
{
    Name = "New Item",
    Description = "Item description"
};

var created = await _downstreamApi.PostForUserAsync<CreateItemRequest, CreatedItem>(
    "MyAPI",
    newItem,
    options => options.RelativePath = "api/items");

PUT- en DELETE-aanvragen verzenden

Resources in de downstream-API bijwerken of verwijderen.

// PUT request
var updated = await _downstreamApi.PutForUserAsync<UpdateRequest, UpdatedItem>(
    "MyAPI",
    updateData,
    options => options.RelativePath = "api/items/123");

// DELETE request
await _downstreamApi.DeleteForUserAsync(
    "MyAPI",
    null,
    options => options.RelativePath = "api/items/123");

Meer informatie over aangepaste API-aanroepen


IAuthorizationHeaderProvider (geavanceerd) gebruiken

Gebruik IAuthorizationHeaderProvidervoor maximale controle over HTTP-aanvragen.

De HTTP-client registreren

Registreer een benoemde HTTP-client voor uw downstream-API.

builder.Services.AddHttpClient("MyAPI", client =>
{
    client.BaseAddress = new Uri("https://myapi.example.com");
});

Aangepaste HTTP-aanvragen maken

HTTP-aanvragen bouwen en verzenden met aangepaste headers en autorisatie.

using Microsoft.Identity.Abstractions;

public class CustomApiService
{
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly IHttpClientFactory _httpClientFactory;

    public CustomApiService(
        IAuthorizationHeaderProvider authProvider,
        IHttpClientFactory httpClientFactory)
    {
        _authProvider = authProvider;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<MyData> GetDataAsync()
    {
        // Get authorization header
        var authHeader = await _authProvider.CreateAuthorizationHeaderForUserAsync(
            new[] { "api://my-api-id/access_as_user" });

        // Create HTTP request with custom logic
        var client = _httpClientFactory.CreateClient("MyAPI");
        var request = new HttpRequestMessage(HttpMethod.Get, "api/resource");
        request.Headers.Add("Authorization", authHeader);
        request.Headers.Add("X-Custom-Header", "custom-value");

        var response = await client.SendAsync(request);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<MyData>();
    }
}

Meer informatie over aangepaste HTTP-logica


Wanneer u downstream-API's aanroept, moet uw toepassing mogelijk scenario's afhandelen waarin gebruikersinteractie is vereist. Dit gebeurt in drie hoofdscenario's:

  1. Incrementele toestemming : aanvullende machtigingen aanvragen buiten wat aanvankelijk is verleend
  2. Voorwaardelijke toegang : voldoen aan beveiligingsvereisten zoals MFA, apparaatcompatibiliteit of locatiebeleid
  3. Verwijdering van tokencache : de tokencache opnieuw vullen nadat de toepassing opnieuw is opgestart of de cache is verlopen

Microsoft. Identity.Web biedt automatische verwerking van deze scenario's met minimale code vereist.

Inzicht in de flow

Wanneer Microsoft. Identity.Web detecteert dat gebruikersinteractie nodig is en genereert een MicrosoftIdentityWebChallengeUserException. Het framework verwerkt dit automatisch via het [AuthorizeForScopes] kenmerk of de MicrosoftIdentityConsentAndConditionalAccessHandler service (voor Blazor), die:

  1. Hiermee wordt de gebruiker omgeleid naar Microsoft Entra ID voor toestemming/verificatie
  2. De oorspronkelijke aanvraag-URL behouden
  3. Retourneert de gebruiker naar de beoogde bestemming nadat het proces is voltooid
  4. Slaat de zojuist verkregen tokens in de cache op

Vereisten bekijken

Als u automatische verwerking van toestemming wilt inschakelen, moet u ervoor zorgen dat uw Program.cs configuratie de volgende configuratie bevat.

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("MyAPI", builder.Configuration.GetSection("MyAPI"))
    .AddInMemoryTokenCaches();

// For MVC applications - enables the account controller
builder.Services.AddControllersWithViews()
    .AddMicrosoftIdentityUI();

// Ensure routes are mapped
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers(); // Required for AccountController

[AuthorizeForScopes] toepassen in MVC-controllers

Het [AuthorizeForScopes] kenmerk, ingesteld op controllers of controlleracties, behandelt automatisch MicrosoftIdentityWebChallengeUserException door de gebruiker uit te dagen wanneer er extra machtigingen nodig zijn.

Bereiken inline declareren

Geef de vereiste bereiken rechtstreeks in het kenmerk op.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;
using Microsoft.Identity.Abstractions;

[Authorize]
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public class ProfileController : Controller
{
    private readonly IDownstreamApi _downstreamApi;

    public ProfileController(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    public async Task<IActionResult> Index()
    {
        // AuthorizeForScopes automatically handles consent challenges
        var userData = await _downstreamApi.GetForUserAsync<UserData>(
            "MyAPI",
            options => options.RelativePath = "api/profile");

        return View(userData);
    }

    // Different action requires additional scopes
    [AuthorizeForScopes(Scopes = new[] { "user.read", "mail.read" })]
    public async Task<IActionResult> Emails()
    {
        var emails = await _downstreamApi.GetForUserAsync<EmailList>(
            "GraphAPI",
            options => options.RelativePath = "me/messages");

        return View(emails);
    }
}

Scopes configureren vanuit appsettings

Bewaar bereiken in appsettings.json voor betere onderhoudbaarheid:

appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "common",
    "ClientId": "[Your-Client-ID]",
    "ClientCredentials": [
      {
        "SourceType": "ClientSecret",
        "ClientSecret": "[Your-Client-Secret]"
      }
    ]
  },
  "DownstreamApis": {
    "TodoList": {
      "BaseUrl": "https://localhost:5001",
      "Scopes": [ "api://[API-Client-ID]/access_as_user" ]
    },
    "GraphAPI": {
      "BaseUrl": "https://graph.microsoft.com/v1.0",
      "Scopes": [ "https://graph.microsoft.com/Mail.Read", "https://graph.microsoft.com/Mail.Send" ]
    }
  }
}

Controller:

[Authorize]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApis:TodoList:Scopes:0")]
public class TodoListController : Controller
{
    private readonly IDownstreamApi _downstreamApi;

    public TodoListController(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    public async Task<IActionResult> Index()
    {
        var todos = await _downstreamApi.GetForUserAsync<IEnumerable<TodoItem>>(
            "TodoList",
            options => options.RelativePath = "api/todolist");

        return View(todos);
    }

    [AuthorizeForScopes(ScopeKeySection = "DownstreamApis:GraphAPI:Scopes:0")]
    public async Task<IActionResult> EmailTodos()
    {
        // If user hasn't consented to Mail.Send, they'll be prompted
        await _downstreamApi.PostForUserAsync<EmailMessage, object>(
            "GraphAPI",
            new EmailMessage { /* ... */ },
            options => options.RelativePath = "me/sendMail");

        return RedirectToAction("Index");
    }
}

Microsoft Entra Externe id configureren met gebruikersstromen

Geef voor B2C-toepassingen (External ID) met meerdere gebruikersstromen de gebruikersstroom op in het kenmerk.

[Authorize]
public class AccountController : Controller
{
    private const string SignUpSignInFlow = "b2c_1_susi";
    private const string EditProfileFlow = "b2c_1_edit_profile";
    private const string ResetPasswordFlow = "b2c_1_reset";

    [AuthorizeForScopes(
        ScopeKeySection = "DownstreamApis:TodoList:Scopes:0",
        UserFlow = SignUpSignInFlow)]
    public async Task<IActionResult> Index()
    {
        var data = await _downstreamApi.GetForUserAsync<UserData>(
            "TodoList",
            options => options.RelativePath = "api/data");

        return View(data);
    }

    [AuthorizeForScopes(
        Scopes = new[] { "openid", "offline_access" },
        UserFlow = EditProfileFlow)]
    public async Task<IActionResult> EditProfile()
    {
        // This triggers the B2C edit profile flow
        return RedirectToAction("Index");
    }
}

[AuthorizeForScopes] toepassen in Razor Pages

Toepassen [AuthorizeForScopes] op de paginamodelklasse:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Identity.Web;
using Microsoft.Identity.Abstractions;

[Authorize]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApis:MyAPI:Scopes:0")]
public class IndexModel : PageModel
{
    private readonly IDownstreamApi _downstreamApi;

    public UserData UserData { get; set; }

    public IndexModel(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    public async Task OnGetAsync()
    {
        // Automatically handles consent challenges
        UserData = await _downstreamApi.GetForUserAsync<UserData>(
            "MyAPI",
            options => options.RelativePath = "api/profile");
    }
}

Blazor Server-toepassingen vereisen expliciete verwerking van uitzonderingen met behulp van de MicrosoftIdentityConsentAndConditionalAccessHandler service.

Program.cs configureren

Registreer de toestemmingshandler voor Blazor Server in uw opstartcode.

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApis("TodoList", builder.Configuration.GetSection("DownstreamApis"))
    .AddInMemoryTokenCaches();

// Register the consent handler for Blazor
builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();

Het Blazor-onderdeel maken

Verpakt API-aanroepen in try-catch-blokken en gebruik ConsentHandler.HandleException() om toestemmingsproblemen af te handelen.

@page "/todolist"
@using Microsoft.Identity.Web
@using Microsoft.Identity.Abstractions
@using MyApp.Models

@inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
@inject IDownstreamApi DownstreamApi

<h3>My Todo List</h3>

@if (todos == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <ul>
        @foreach (var todo in todos)
        {
            <li>@todo.Title</li>
        }
    </ul>
}

@code {
    private IEnumerable<TodoItem> todos;

    protected override async Task OnInitializedAsync()
    {
        await LoadTodosAsync();
    }

    [AuthorizeForScopes(ScopeKeySection = "DownstreamApis:TodoList:Scopes:0")]
    private async Task LoadTodosAsync()
    {
        try
        {
            todos = await DownstreamApi.GetForUserAsync<IEnumerable<TodoItem>>(
                "TodoList",
                options => options.RelativePath = "api/todolist");
        }
        catch (Exception ex)
        {
            // Handles MicrosoftIdentityWebChallengeUserException
            // and initiates user consent/authentication flow
            ConsentHandler.HandleException(ex);
        }
    }

    private async Task AddTodoAsync(string title)
    {
        try
        {
            await DownstreamApi.PostForUserAsync<TodoItem, TodoItem>(
                "TodoList",
                new TodoItem { Title = title },
                options => options.RelativePath = "api/todolist");

            await LoadTodosAsync();
        }
        catch (Exception ex)
        {
            ConsentHandler.HandleException(ex);
        }
    }
}

Uitzonderingen handmatig verwerken (geavanceerd)

Als u aangepaste logica voor toestemmingsstromen nodig hebt, moet u het volgende expliciet afhandelen MicrosoftIdentityWebChallengeUserException :

[Authorize]
public class AdvancedController : Controller
{
    private readonly IDownstreamApi _downstreamApi;
    private readonly ILogger<AdvancedController> _logger;

    public AdvancedController(
        IDownstreamApi downstreamApi,
        ILogger<AdvancedController> logger)
    {
        _downstreamApi = downstreamApi;
        _logger = logger;
    }

    public async Task<IActionResult> SendEmail()
    {
        try
        {
            await _downstreamApi.PostForUserAsync<EmailMessage, object>(
                "GraphAPI",
                new EmailMessage
                {
                    Subject = "Test",
                    Body = "Test message"
                },
                options => options.RelativePath = "me/sendMail");

            return RedirectToAction("Success");
        }
        catch (MicrosoftIdentityWebChallengeUserException ex)
        {
            // Log the consent requirement
            _logger.LogWarning(
                "Consent required for scopes: {Scopes}. Challenging user.",
                string.Join(", ", ex.Scopes));

            // Custom properties for redirect
            var properties = new AuthenticationProperties
            {
                RedirectUri = Url.Action("SendEmail", "Advanced"),
            };

            // Add custom state if needed
            properties.Items["consent_attempt"] = "1";

            return Challenge(properties, OpenIdConnectDefaults.AuthenticationScheme);
        }
        catch (HttpRequestException ex)
        {
            _logger.LogError(ex, "Failed to send email");
            return View("Error");
        }
    }
}

Scenario's voor voorwaardelijke toegang verwerken

Beleidsregels voor voorwaardelijke toegang kunnen aanvullende verificatiefactoren vereisen. De verwerking is identiek aan incrementele toestemming:

[Authorize]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApis:SecureAPI:Scopes:0")]
public class SecureDataController : Controller
{
    private readonly IDownstreamApi _downstreamApi;

    public SecureDataController(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    public async Task<IActionResult> Index()
    {
        // If conditional access requires MFA, AuthorizeForScopes
        // automatically challenges the user
        var sensitiveData = await _downstreamApi.GetForUserAsync<SensitiveData>(
            "SecureAPI",
            options => options.RelativePath = "api/sensitive");

        return View(sensitiveData);
    }
}

Veelvoorkomende triggers voor voorwaardelijke toegang:

  • Multifactorverificatie (MFA)
  • Compatibele apparaatvereiste
  • Vertrouwde netwerklocatie
  • Acceptatie van gebruiksvoorwaarden
  • Wachtwoordwijzigingsvereiste

Best practices volgen

Pas deze aanbevelingen toe bij het implementeren van toestemming en voorwaardelijke toegang.

Gebruiken [AuthorizeForScopes] - Eenvoudigste aanpak voor MVC-controllers en Razor Pages

Scopes opslaan in configuratie - Gebruik ScopeKeySection = "DownstreamApis:ApiName:Scopes:0" om naar de scopes in appsettings.json te verwijzen

Toepassen op controllerniveau - Standaardbereiken instellen op de controller, overschrijven op specifieke acties

Uitzonderingen verwerken in Blazor - Pak API-aanroepen altijd in met try-catch en gebruik ConsentHandler.HandleException()

Uitzonderingen opnieuw gooien - Als u MicrosoftIdentityWebChallengeUserException opvangt, gooi het opnieuw zodat [AuthorizeForScopes] het kan verwerken

Voorwaardelijke toegang testen - Controleer of uw app MFA en ander CA-beleid correct verwerkt

Uitzonderingen niet onderdrukken - Het vangen zonder opnieuw gooien onderbreekt de toestemmingsstroom

Sla reacties niet voor onbepaalde tijd in de cache op : tokens verlopen; ontwerp voor opnieuw verificatie


Statische machtigingen (beheerderstoestemming)

Alle machtigingen worden aangevraagd tijdens de app-registratie en toestemming van een tenantbeheerder:

Voordelen:

  • Gebruikers zien nooit toestemmingsprompts
  • Vereist voor Microsoft apps van derden
  • Eenvoudigere gebruikerservaring

nadelen:

  • Vereist betrokkenheid van tenantbeheerders
  • Overgeprivilegieerd vanaf het begin
  • Minder flexibel voor scenario's met meerdere tenants

Configuration:

// Request all pre-approved scopes for Microsoft Graph
var scopes = new[] { "https://graph.microsoft.com/.default" };

var userData = await _downstreamApi.GetForUserAsync<UserData>(
    "GraphAPI",
    options =>
    {
        options.RelativePath = "me";
        options.Scopes = scopes; // Use .default scope
    });

Incrementele toestemming (dynamisch)

Tijdens runtime worden machtigingen aangevraagd:

Voordelen:

  • Betere beveiliging (principe van minimale bevoegdheden)
  • Gebruikers geven toestemming voor wat ze daadwerkelijk gebruiken
  • Werkt voor apps met meerdere tenants

nadelen:

  • Gebruikers kunnen worden onderbroken met toestemmingsprompts
  • Verwerking vereist MicrosoftIdentityWebChallengeUserException

Aanbeveling: Incrementele toestemming gebruiken voor toepassingen met meerdere tenants; statische machtigingen gebruiken voor zakelijke apps van derden waarbij beheerderstoestemming wordt gegarandeerd


Tokencaching configureren

Microsoft. Identity.Web slaat tokens in de cache op om de prestaties te verbeteren en aanroepen tot Microsoft Entra te verminderen.

Cache in het geheugen gebruiken (standaard)

Voeg een in-memory tokencache toe voor ontwikkelings- of scenario's met één server.

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches(); // In-memory cache

Gebruiken voor:

  • Ontwikkeling
  • Implementaties met één server
  • Kleine gebruikersbasis

Limitations:

  • Niet gedeeld tussen instanties
  • Verloren bij opnieuw opstarten van de app
  • Geheugenverbruik groeit met gebruikers

Configureer een gedistribueerde cache, zoals Redis of SQL Server voor productie-implementaties.

// Install: Microsoft.Identity.Web.TokenCache

// Redis
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration["Redis:ConnectionString"];
    options.InstanceName = "MyApp_";
});

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

// SQL Server
builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration["SqlCache:ConnectionString"];
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";
});

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

Gebruiken voor:

  • Implementaties met meerdere servers (taakverdeling)
  • Scenario's voor hoge beschikbaarheid
  • Grote gebruikersbasis
  • Permanente cache bij herstarten

Fouten bij het verkrijgen van tokens afhandelen

Veelvoorkomende uitzonderingen afhandelen

De volgende code laat zien hoe u de meest voorkomende uitzonderingen voor het verkrijgen van tokens kunt ondervangen en afhandelen.

try
{
    var data = await _downstreamApi.GetForUserAsync<MyData>(
        "MyAPI",
        options => options.RelativePath = "api/resource");
}
catch (MicrosoftIdentityWebChallengeUserException ex)
{
    // User needs to consent or reauthenticate
    _logger.LogWarning($"User consent required: {ex.Message}");
    return Challenge(new AuthenticationProperties { RedirectUri = Request.Path });
}
catch (MsalUiRequiredException ex)
{
    // User interaction required (sign-in again, MFA, etc.)
    _logger.LogWarning($"User interaction required: {ex.Message}");
    return Challenge(OpenIdConnectDefaults.AuthenticationScheme);
}
catch (MsalServiceException ex)
{
    // Service error (Microsoft Entra ID unavailable, etc.)
    _logger.LogError(ex, "Microsoft Entra ID service error");
    return StatusCode(503, "Authentication service temporarily unavailable");
}
catch (HttpRequestException ex)
{
    // Downstream API unreachable
    _logger.LogError(ex, "Downstream API call failed");
    return StatusCode(503, "Downstream service unavailable");
}

Gecontroleerde degradatie implementeren

Laad optionele gegevens van downstream-API's en ga terug naar de standaardinstellingen wanneer aanroepen mislukken.

public async Task<IActionResult> Dashboard()
{
    var model = new DashboardModel();

    // Try to load optional data from downstream API
    try
    {
        model.EnrichedData = await _downstreamApi.GetForUserAsync<EnrichedData>(
            "MyAPI",
            options => options.RelativePath = "api/enriched");
    }
    catch (Exception ex)
    {
        _logger.LogWarning(ex, "Failed to load enriched data, using defaults");
        model.EnrichedData = new EnrichedData { /* defaults */ };
    }

    return View(model);
}

OWIN (.NET Framework) implementeren

Volg deze stappen voor webtoepassingen op basis van OWIN in .NET Framework.

1. Pakketten installeren

Installeer de vereiste NuGet-pakketten.

Install-Package Microsoft.Identity.Web.OWIN
Install-Package Microsoft.Owin.Host.SystemWeb

2. Opstartproces configureren

Configureer Microsoft Entra authenticatie en tokenverwerving in de OWIN-startklasse.

using Microsoft.Identity.Web;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Owin;

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        app.AddMicrosoftIdentityWebApp(
            Configuration,
            configSectionName: "AzureAd",
            openIdConnectScheme: "OpenIdConnect",
            cookieScheme: CookieAuthenticationDefaults.AuthenticationType,
            subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: true);

        app.EnableTokenAcquisitionToCallDownstreamApi();
        app.AddDistributedTokenCaches();
    }
}

3. Downstream-API aanroepen

Een token verkrijgen en de downstream-API aanroepen vanaf een MVC-controller.

using Microsoft.Identity.Web;
using System.Threading.Tasks;
using System.Web.Mvc;

[Authorize]
public class ProfileController : Controller
{
    public async Task<ActionResult> Index()
    {
        var downstreamApi = TokenAcquirerFactory.GetDefaultInstance()
            .GetTokenAcquirer()
            .GetDownstreamApi();

        var userData = await downstreamApi.GetForUserAsync<UserData>(
            "MyAPI",
            options => options.RelativePath = "api/profile");

        return View(userData);
    }
}

Note: OWIN-ondersteuning verschilt van ASP.NET Core. Zie de OWIN-documentatie voor meer informatie.


Best practices voor beveiliging volgen

Bereiken beheren

Pas het principe van minimale bevoegdheden toe bij het aanvragen van API-machtigingen.

Do:

  • Alleen de scopes vragen die u nodig hebt
  • Incrementele toestemming gebruiken voor geavanceerde functies
  • Vereiste bereiken documenteer in uw app

Don't:

  • Onnodige bereiken vooraf aanvragen
  • Admin-only scopes aanvragen zonder rechtvaardiging
  • Stel dat alle toegangsniveaus zullen worden toegekend

Tokens veilig verwerken

Volg deze richtlijnen om toegangstokens in uw toepassing te beveiligen.

Do:

  • Laat Microsoft.Identity.Web de tokens beheren
  • Gedistribueerde cache gebruiken in productie
  • Fouten bij het verkrijgen van tokens soepel afhandelen

Don't:

  • Tokens zelf opslaan
  • Toegangstokens voor logboeken
  • Tokens verzenden naar client-side code

Afhandeling van fouten

Implementeer robuuste foutafhandeling voor verificatie- en API-aanroepfouten.

Do:

  • Uitzonderingen voor toestemming ondervangen en afhandelen
  • Duidelijke foutberichten voor gebruikers opgeven
  • Fouten loggen voor foutopsporing

Don't:

  • Tokenfouten beschikbaar maken voor gebruikers
  • Api-aanroepen op de achtergrond mislukken
  • Verificatie-uitzonderingen negeren

Veelvoorkomende problemen oplossen

Bekijk deze oplossingen voor veelvoorkomende verificatiefouten.

Probleem: 'AADSTS65001: De gebruiker of beheerder heeft geen toestemming gegeven'

Oorzaak: De gebruiker heeft geen toestemming gegeven voor vereiste machtigingen.

Solution:

catch (MicrosoftIdentityWebChallengeUserException ex)
{
    // Redirect to consent page
    return Challenge(
        new AuthenticationProperties { RedirectUri = Request.Path },
        OpenIdConnectDefaults.AuthenticationScheme);
}

Probleem: 'AADSTS50076: Multi-Factor Authentication vereist'

Oorzaak: De gebruiker moet MFA voltooien.

Solution:

catch (MsalUiRequiredException)
{
    // Redirect user to sign in with MFA
    return Challenge(OpenIdConnectDefaults.AuthenticationScheme);
}

Probleem: Tokens blijven niet behouden tijdens het opnieuw opstarten van de app

Oorzaak: In-memory cache gebruiken.

Solution: Overschakelen naar gedistribueerde cache (Redis, SQL Server of Cosmos DB).

Probleem: 401 Niet geautoriseerd vanuit downstream-API

Mogelijke oorzaken:

  • Verkeerde bereiken aangevraagd
  • API-machtiging niet verleend in app-registratie
  • Token is verlopen

Solution:

  1. Toepassingsbereiken in appsettings.json controleren op overeenstemming met API-vereisten
  2. Controleren of app-registratie API-machtigingen heeft
  3. Zorg ervoor dat tokens in de cache worden opgeslagen en vernieuwd.

Voor gedetailleerde diagnostische gegevens: Zie de handleiding logboekregistratie en diagnostische gegevens voor correlatie-id's, foutopsporing in tokencache en uitgebreide patronen voor probleemoplossing.


Prestaties optimaliseren

Strategie voor tokencaching plannen

Selecteer een cachestrategie die overeenkomt met uw implementatietopologie.

  • Gedistribueerde cache gebruiken voor implementaties met meerdere servers
  • De juiste verlooptijd van de cache configureren
  • Cacheprestaties bewaken

Tokenaanvragen minimaliseren

Microsoft. Identity.Web slaat tokens automatisch in de cache op. Beide aanroepen in het volgende voorbeeld gebruiken hetzelfde token in de cache.

// Bad: Multiple token acquisitions
var profile = await _downstreamApi.GetForUserAsync<Profile>(
    "API",
    options => options.RelativePath = "profile");
var settings = await _downstreamApi.GetForUserAsync<Settings>(
    "API",
    options => options.RelativePath = "settings");

// Good: Single token, multiple calls (token is cached)
// Both calls use the same cached token
var profile = await _downstreamApi.GetForUserAsync<Profile>(
    "API",
    options => options.RelativePath = "profile");
var settings = await _downstreamApi.GetForUserAsync<Settings>(
    "API",
    options => options.RelativePath = "settings");

Parallelle API-aanroepen uitvoeren

Roep meerdere downstream-API's gelijktijdig aan om de totale latentie te verminderen.

// Call multiple APIs in parallel
var profileTask = _downstreamApi.GetForUserAsync<Profile>(
    "API1",
    options => options.RelativePath = "profile");
var settingsTask = _downstreamApi.GetForUserAsync<Settings>(
    "API2",
    options => options.RelativePath = "settings");

await Task.WhenAll(profileTask, settingsTask);

var profile = profileTask.Result;
var settings = settingsTask.Result;

Aanvullende richtlijnen voor gerelateerde scenario's zoeken.