Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wywołaj Microsoft Graph z aplikacji ASP.NET Core i OWIN przy użyciu Microsoft.Identity.Web i Microsoft Graph SDK w celu uzyskania dostępu do danych i usług Microsoft 365.
Omówienie integracji Microsoft Graph
Microsoft Graph zapewnia ujednolicony punkt końcowy interfejsu API umożliwiający uzyskiwanie dostępu do danych między Microsoft 365, Windows i Enterprise Mobility + Security. Microsoft.Identity.Web upraszcza uwierzytelnianie i pozyskiwanie tokenów dla Microsoft Graph, a zestaw SDK Microsoft Graph zapewnia płynny, typowany interfejs API do wywoływania punktów końcowych Microsoft Graph.
Wybierz pozycję Microsoft. Identity.Web.GraphServiceClient
Poniższe korzyści sprawiają, że Microsoft.Identity.Web.GraphServiceClient jest zalecanym podejściem do wywoływania Microsoft Graph.
- Automatyczne pozyskiwanie tokenów: bezproblemowo obsługuje tokeny użytkowników i aplikacji
- Wbudowane buforowanie tokenów dla poprawy wydajności
- Interfejs API Fluent: bezpieczne dla typu, przyjazne dla funkcji IntelliSense wywołania grafu
- Zgoda przyrostowa: żądanie dodatkowych zakresów na żądanie
- Wiele schematów uwierzytelniania: obsługa aplikacji internetowych i internetowych interfejsów API
- Zarówno wersja 1.0, jak i Beta: używaj stabilnych i przeglądowych punktów końcowych razem
Instalowanie wymaganych pakietów
Zainstaluj pakiet integracyjny zestawu SDK Microsoft Graph:
dotnet add package Microsoft.Identity.Web.GraphServiceClient
W przypadku interfejsów API Microsoft Graph Beta:
dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta
Konfigurowanie ASP.NET Core
1. Konfigurowanie usług
Dodaj obsługę Microsoft Graph do aplikacji:
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add authentication (web app or web API)
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
// Add Microsoft Graph support
builder.Services.AddMicrosoftGraph();
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
2. Konfigurowanie appsettings.json
Skonfiguruj opcje programu Graph w pliku konfiguracji:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"CallbackPath": "/signin-oidc"
},
"DownstreamApis": {
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": ["User.Read", "User.ReadBasic.All"]
}
}
}
Konfiguracja z kodem:
builder.Services.AddMicrosoftGraph(options =>
{
builder.Configuration.GetSection("DownstreamApis:MicrosoftGraph").Bind(options);
});
Możesz też skonfigurować bezpośrednio w kodzie:
builder.Services.AddMicrosoftGraph();
builder.Services.Configure<MicrosoftGraphOptions>(options =>
{
options.BaseUrl = "https://graph.microsoft.com/v1.0";
options.Scopes = new[] { "User.Read", "Mail.Read" };
});
3. Konfigurowanie obsługi chmury krajowej
Aby użyć Microsoft Graph w chmurach krajowych, określ element BaseUrl w konfiguracji:
{
"DownstreamApis": {
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.us/v1.0",
"Scopes": ["User.Read"]
}
}
}
Zobacz wdrożenia Microsoft Graph dla adresów URL punktów końcowych.
Korzystanie z GraphServiceClient
Wstrzykiwanie GraphServiceClient
Wstrzyknij GraphServiceClient z konstruktora:
using Microsoft.Graph;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[Authorize]
public class ProfileController : Controller
{
private readonly GraphServiceClient _graphClient;
public ProfileController(GraphServiceClient graphClient)
{
_graphClient = graphClient;
}
public async Task<IActionResult> Index()
{
// Call Microsoft Graph
var user = await _graphClient.Me.GetAsync();
return View(user);
}
}
Korzystanie z uprawnień delegowanych (tokenów użytkowników)
Wywołaj program Graph w imieniu zalogowanego użytkownika z delegowanymi uprawnieniami.
Pobieranie podstawowego profilu użytkownika
Pobierz informacje o profilu bieżącego użytkownika z Microsoft Graph.
[Authorize]
public class ProfileController : Controller
{
private readonly GraphServiceClient _graphClient;
public ProfileController(GraphServiceClient graphClient)
{
_graphClient = graphClient;
}
public async Task<IActionResult> Me()
{
// Get current user's profile
var user = await _graphClient.Me.GetAsync();
return View(new UserViewModel
{
DisplayName = user.DisplayName,
Mail = user.Mail,
JobTitle = user.JobTitle
});
}
}
Żądanie zgody przyrostowej
Żądaj dodatkowych zakresów dynamicznie, gdy aplikacja ich potrzebuje:
[Authorize]
[AuthorizeForScopes("Mail.Read")]
public class MailController : Controller
{
private readonly GraphServiceClient _graphClient;
public MailController(GraphServiceClient graphClient)
{
_graphClient = graphClient;
}
public async Task<IActionResult> Inbox()
{
try
{
// Request Mail.Read scope dynamically
var messages = await _graphClient.Me.Messages
.GetAsync(r => r.Options.WithScopes("Mail.Read"));
return View(messages);
}
catch (MicrosoftIdentityWebChallengeUserException)
{
// ASP.NET Core will redirect user to consent
// thansk to the AuthorizeForScopes attribute.
throw;
}
}
}
Stosowanie opcji zapytania
Użyj opcji zapytań zestawu Graph SDK, aby filtrować, wybierać i porządkować wyniki:
public async Task<IActionResult> UnreadMessages()
{
var messages = await _graphClient.Me.Messages
.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Filter = "isRead eq false";
requestConfiguration.QueryParameters.Select = new[] { "subject", "from", "receivedDateTime" };
requestConfiguration.QueryParameters.Orderby = new[] { "receivedDateTime desc" };
requestConfiguration.QueryParameters.Top = 10;
// Request specific scope
requestConfiguration.Options.WithScopes("Mail.Read");
});
return View(messages);
}
Przeglądaj wyniki strona po stronie
Obsłuż stronicowane wyniki z Microsoft Graph, iterując po każdej stronie:
public async Task<IActionResult> AllUsers()
{
var allUsers = new List<User>();
// Get first page
var users = await _graphClient.Users
.GetAsync(r => r.Options.WithScopes("User.ReadBasic.All"));
// Add first page
allUsers.AddRange(users.Value);
// Iterate through remaining pages
var pageIterator = PageIterator<User, UserCollectionResponse>
.CreatePageIterator(
_graphClient,
users,
user =>
{
allUsers.Add(user);
return true; // Continue iteration
});
await pageIterator.IterateAsync();
return View(allUsers);
}
Używanie uprawnień aplikacji (tokenów tylko dla aplikacji)
Wywołaj program Graph z uprawnieniami aplikacji, jeśli kontekst użytkownika nie jest wymagany.
Wywoływanie grafu za pomocą funkcji WithAppOnly()
WithAppOnly() Użyj metody , aby wykonywać wywołania programu Graph z uprawnieniami aplikacji.
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AdminController : ControllerBase
{
private readonly GraphServiceClient _graphClient;
public AdminController(GraphServiceClient graphClient)
{
_graphClient = graphClient;
}
[HttpGet("users/count")]
public async Task<ActionResult<int>> GetUserCount()
{
// Get count using app permissions
var count = await _graphClient.Users.Count
.GetAsync(r => r.Options.WithAppOnly());
return Ok(count);
}
[HttpGet("applications")]
public async Task<ActionResult> GetApplications()
{
// List applications using app permissions
var apps = await _graphClient.Applications
.GetAsync(r => r.Options.WithAppOnly());
return Ok(apps.Value);
}
}
Konfigurowanie uprawnień aplikacji
Określ żądanie tokenu aplikacji w appsettings.json:
{
"DownstreamApis": {
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"RequestAppToken": true
}
}
}
Zakresy zostaną automatycznie ustawione na ["https://graph.microsoft.com/.default"].
Konfigurowanie szczegółowych opcji tylko dla aplikacji
Ustaw jawne opcje uwierzytelniania tylko dla aplikacji w kodzie.
public async Task<IActionResult> GetApplicationsDetailed()
{
var apps = await _graphClient.Applications
.GetAsync(r =>
{
r.Options.WithAuthenticationOptions(options =>
{
// Request app token explicitly
options.RequestAppToken = true;
// Scopes automatically become [.default]
// No need to specify: options.Scopes = new[] { "https://graph.microsoft.com/.default" };
});
});
return Ok(apps);
}
Obsługa wielu schematów uwierzytelniania
Jeśli aplikacja używa wielu schematów uwierzytelniania (na przykład aplikacji internetowej i interfejsu API), określ schemat do użycia:
using Microsoft.AspNetCore.Authentication.JwtBearer;
[Authorize]
public class ApiDataController : ControllerBase
{
private readonly GraphServiceClient _graphClient;
public ApiDataController(GraphServiceClient graphClient)
{
_graphClient = graphClient;
}
[HttpGet("profile")]
public async Task<ActionResult> GetProfile()
{
// Specify JWT Bearer scheme
var user = await _graphClient.Me
.GetAsync(r => r.Options
.WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme));
return Ok(user);
}
}
Konfigurowanie szczegółowych opcji schematu
Ustaw jawnie schemat uwierzytelniania i zakresy w kodzie.
public async Task<ActionResult> GetMailWithScheme()
{
var messages = await _graphClient.Me.Messages
.GetAsync(r =>
{
r.Options.WithAuthenticationOptions(options =>
{
// Specify authentication scheme
options.AcquireTokenOptions.AuthenticationOptionsName =
JwtBearerDefaults.AuthenticationScheme;
// Specify scopes
options.Scopes = new[] { "Mail.Read" };
});
});
return Ok(messages);
}
Użyj zarówno punktów końcowych v1.0, jak i beta.
Zarejestruj się i wywołaj zarówno Microsoft Graph w wersji 1.0, jak i beta w tej samej aplikacji.
1. Zainstaluj oba pakiety
dotnet add package Microsoft.Identity.Web.GraphServiceClient
dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta
2. Rejestrowanie obu usług
using Microsoft.Identity.Web;
builder.Services.AddMicrosoftGraph();
builder.Services.AddMicrosoftGraphBeta();
3. Użyj obu klientów
using GraphServiceClient = Microsoft.Graph.GraphServiceClient;
using GraphBetaServiceClient = Microsoft.Graph.Beta.GraphServiceClient;
public class MyController : Controller
{
private readonly GraphServiceClient _graphClient;
private readonly GraphBetaServiceClient _graphBetaClient;
public MyController(
GraphServiceClient graphClient,
GraphBetaServiceClient graphBetaClient)
{
_graphClient = graphClient;
_graphBetaClient = graphBetaClient;
}
public async Task<IActionResult> GetData()
{
// Use stable v1.0 endpoint
var user = await _graphClient.Me.GetAsync();
// Use beta endpoint for preview features
var profile = await _graphBetaClient.Me.Profile.GetAsync();
return View(new { user, profile });
}
}
Wysyłanie żądań wsadowych
Połącz wiele wywołań programu Graph w jedno żądanie HTTP, aby zwiększyć wydajność:
using Microsoft.Graph.Models;
public async Task<IActionResult> GetDashboard()
{
var batchRequestContent = new BatchRequestContentCollection(_graphClient);
// Add multiple requests to batch
var userRequest = _graphClient.Me.ToGetRequestInformation();
var messagesRequest = _graphClient.Me.Messages.ToGetRequestInformation();
var eventsRequest = _graphClient.Me.Events.ToGetRequestInformation();
var userRequestId = await batchRequestContent.AddBatchRequestStepAsync(userRequest);
var messagesRequestId = await batchRequestContent.AddBatchRequestStepAsync(messagesRequest);
var eventsRequestId = await batchRequestContent.AddBatchRequestStepAsync(eventsRequest);
// Send batch request
var batchResponse = await _graphClient.Batch.PostAsync(batchRequestContent);
// Extract responses
var user = await batchResponse.GetResponseByIdAsync<User>(userRequestId);
var messages = await batchResponse.GetResponseByIdAsync<MessageCollectionResponse>(messagesRequestId);
var events = await batchResponse.GetResponseByIdAsync<EventCollectionResponse>(eventsRequestId);
return View(new DashboardViewModel
{
User = user,
Messages = messages.Value,
Events = events.Value
});
}
Stosowanie typowych wzorców grafu
Te wzorce umożliwiają częste wykonywanie operacji Microsoft Graph w aplikacji.
Pobierz menedżera użytkownika
Pobierz menedżera zalogowanego użytkownika z katalogu.
public async Task<IActionResult> GetManager()
{
var manager = await _graphClient.Me.Manager.GetAsync();
// Cast to User (manager is DirectoryObject)
if (manager is User managerUser)
{
return View(managerUser);
}
return NotFound("Manager not found");
}
Pobieranie zdjęcia użytkownika
Pobierz zdjęcie profilu zalogowanego użytkownika w postaci strumienia.
public async Task<IActionResult> GetPhoto()
{
try
{
var photoStream = await _graphClient.Me.Photo.Content.GetAsync();
return File(photoStream, "image/jpeg");
}
catch (ServiceException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return NotFound("Photo not available");
}
}
Wyślij e-mail
Wyślij wiadomość e-mail w imieniu zalogowanego użytkownika.
public async Task<IActionResult> SendEmail([FromBody] EmailRequest request)
{
var message = new Message
{
Subject = request.Subject,
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = request.Body
},
ToRecipients = new List<Recipient>
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = request.ToEmail
}
}
}
};
await _graphClient.Me.SendMail
.PostAsync(new SendMailPostRequestBody
{
Message = message,
SaveToSentItems = true
},
requestConfiguration =>
{
requestConfiguration.Options.WithScopes("Mail.Send");
});
return Ok("Email sent");
}
Tworzenie zdarzenia kalendarza
Utwórz nowe wydarzenie kalendarza z uczestnikami dla zalogowanego użytkownika.
public async Task<IActionResult> CreateEvent([FromBody] EventRequest request)
{
var newEvent = new Event
{
Subject = request.Subject,
Start = new DateTimeTimeZone
{
DateTime = request.StartTime.ToString("yyyy-MM-ddTHH:mm:ss"),
TimeZone = "UTC"
},
End = new DateTimeTimeZone
{
DateTime = request.EndTime.ToString("yyyy-MM-ddTHH:mm:ss"),
TimeZone = "UTC"
},
Attendees = request.Attendees.Select(email => new Attendee
{
EmailAddress = new EmailAddress { Address = email },
Type = AttendeeType.Required
}).ToList()
};
var createdEvent = await _graphClient.Me.Events
.PostAsync(newEvent, r => r.Options.WithScopes("Calendars.ReadWrite"));
return Ok(createdEvent);
}
Wyszukiwanie użytkowników
Wyszukaj użytkowników w katalogu według nazwy wyświetlanej lub adresu e-mail.
public async Task<IActionResult> SearchUsers(string searchTerm)
{
var users = await _graphClient.Users
.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Filter =
$"startswith(displayName,'{searchTerm}') or startswith(mail,'{searchTerm}')";
requestConfiguration.QueryParameters.Select =
new[] { "displayName", "mail", "jobTitle" };
requestConfiguration.QueryParameters.Top = 10;
requestConfiguration.Options.WithScopes("User.ReadBasic.All");
});
return Ok(users.Value);
}
Implementowanie obsługi OWIN
W przypadku aplikacji ASP.NET korzystających z OWIN skonfiguruj fabrykę pozyskiwania tokenów i zarejestruj usługi Microsoft Graph.
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Owin;
public class Startup
{
public void Configuration(IAppBuilder app)
{
OwinTokenAcquirerFactory factory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
app.AddMicrosoftIdentityWebApi(factory);
factory.Services
.AddMicrosoftGraph();
factory.Build();
}
}
2. Wywoływanie interfejsu API z kontrolerów
Pobierz wystąpienie GraphServiceClient w kontrolerze i wywołaj Microsoft Graph.
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using System.Web.Http;
[Authorize]
public class DataController : ApiController
{
public DataController()
{
}
public async Task<IHttpActionResult> GetMyProfile()
{
GraphServiceClient graphServiceClient = this.GetGraphServiceClient();
var me = await graphServiceClient.Me.GetAsync();
return Ok(me);
}
}
Migrowanie z Microsoft. Identity.Web.MicrosoftGraph 2.x
Jeśli przeprowadzasz migrację ze starszego pakietu Microsoft.Identity.Web.MicrosoftGraph (SDK 4.x), zapoznaj się z następującymi kluczowymi zmianami:
1. Usuń stary pakiet i dodaj nowy
dotnet remove package Microsoft.Identity.Web.MicrosoftGraph
dotnet add package Microsoft.Identity.Web.GraphServiceClient
2. Aktualizowanie wywołań metod
W zestawie SDK 5.x metoda .Request() została usunięta.
Przed (SDK 4.x):
var user = await _graphClient.Me.Request().GetAsync();
var messages = await _graphClient.Me.Messages
.Request()
.WithScopes("Mail.Read")
.GetAsync();
Po SDK 5.x:
var user = await _graphClient.Me.GetAsync();
var messages = await _graphClient.Me.Messages
.GetAsync(r => r.Options.WithScopes("Mail.Read"));
3. Zaktualizuj lokalizację WithScopes()
Before:
var users = await _graphClient.Users
.Request()
.WithScopes("User.Read.All")
.GetAsync();
After:
var users = await _graphClient.Users
.GetAsync(r => r.Options.WithScopes("User.Read.All"));
4. Aktualizowanie lokalizacji withAppOnly()
Before:
var apps = await _graphClient.Applications
.Request()
.WithAppOnly()
.GetAsync();
After:
var apps = await _graphClient.Applications
.GetAsync(r => r.Options.WithAppOnly());
5. Zaktualizuj lokalizację WithAuthenticationScheme()
Before:
var user = await _graphClient.Me
.Request()
.WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme)
.GetAsync();
After:
var user = await _graphClient.Me
.GetAsync(r => r.Options
.WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme));
Aby uzyskać szczegółowe informacje na temat migracji, zobacz Microsoft Graph .NET SDK v5 changelog .
Zarządzanie błędami
Obsługa elementu ServiceException
Przechwyć ODataError i MicrosoftIdentityWebChallengeUserException, aby bezpiecznie obsługiwać błędy interfejs Graph API.
using Microsoft.Graph.Models.ODataErrors;
public async Task<IActionResult> GetData()
{
try
{
var user = await _graphClient.Me.GetAsync();
return Ok(user);
}
catch (ODataError ex) when (ex.ResponseStatusCode == 404)
{
return NotFound("Resource not found");
}
catch (ODataError ex) when (ex.ResponseStatusCode == 403)
{
return Forbid("Insufficient permissions");
}
catch (MicrosoftIdentityWebChallengeUserException)
{
// User needs to consent
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Graph API call failed");
return StatusCode(500, "An error occurred");
}
}
Postępuj zgodnie z najlepszymi rozwiązaniami
1. Zażądaj minimalnych zakresów
Proś tylko o zakresy, których potrzebujesz.
// Bad: Requesting too many scopes
options.Scopes = new[] { "User.Read", "Mail.ReadWrite", "Calendars.ReadWrite", "Files.ReadWrite.All" };
// Good: Request only what you need
options.Scopes = new[] { "User.Read" };
Stosuj zgodę przyrostową
Zażądaj dodatkowych zakresów tylko w razie potrzeby:
// Sign-in: Only User.Read
// Later, when accessing mail:
var messages = await _graphClient.Me.Messages
.GetAsync(r => r.Options.WithScopes("Mail.Read"));
3. Cache GraphServiceClient
Klasa GraphServiceClient jest bezpieczna do ponownego użycia. Zarejestruj jako singleton albo wstrzyknij z użyciem DI.
4. Użyj opcji wybierz, aby zmniejszyć rozmiar odpowiedzi
// Bad: Getting all properties
var users = await _graphClient.Users.GetAsync();
// Good: Select only needed properties
var users = await _graphClient.Users
.GetAsync(r => r.QueryParameters.Select =
new[] { "displayName", "mail", "id" });
Rozwiązywanie typowych problemów
Rozwiązywanie problemu "Niewystarczające uprawnienia do ukończenia operacji"
Przyczyna: Aplikacja nie ma wymaganych uprawnień programu Graph.
Rozwiązanie:
- Dodaj wymagane uprawnienia interfejsu API w ramach rejestracji aplikacji
- Zgoda administratora wymagana dla uprawnień aplikacji
- Zgoda użytkownika wymagana dla uprawnień delegowanych
Rozwiąż problem "AADSTS65001: użytkownik lub administrator nie wyraził zgody"
Przyczyna: Użytkownik nie wyraził zgody na żądane zakresy.
Rozwiązanie: Stosuj zgodę przyrostową z .WithScopes(), aby wyzwolić przepływ zgody.
Rozwiązywanie problemów ze zdjęciem 404
Przyczyna: Użytkownik nie ma zdjęcia profilowego.
Rozwiązanie: Obsłuż błąd 404 w sposób bezpieczny i zastosuj domyślny awatar.
Rozwiązać błędy żądań wsadowych
Przyczyna: Pojedyncze żądania w partii mogą niezależnie zakończyć się niepowodzeniem.
Rozwiązanie: Sprawdź każdą odpowiedź w partii pod kątem błędów:
var userResponse = await batchResponse.GetResponseByIdAsync<User>(userRequestId);
if (userResponse == null)
{
// Handle individual request failure
}
Treści powiązane
- dokumentacja Microsoft Graph
- Przewodnik migracji zestawu Graph SDK w wersji 5
- Wywoływanie podrzędnych interfejsów API: omówienie
- Wywoływanie z aplikacji internetowych
- Wywoływanie z internetowych interfejsów API
Kolejne kroki: Dowiedz się o wywoływaniu Azure SDK lub niestandardowych API.