Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Utilize o Microsoft Graph a partir das suas aplicações ASP.NET Core e OWIN utilizando o Microsoft.Identity.Web e o Microsoft Graph SDK para aceder a dados e serviços do Microsoft 365.
Compreender a integração com Microsoft Graph
O Microsoft Graph fornece um endpoint API unificado para aceder a dados através do Microsoft 365, Windows e Enterprise Mobility + Security. Microsoft.Identity.Web simplifica a autenticação e aquisição de tokens para o Microsoft Graph, enquanto o Microsoft Graph SDK fornece uma API intuitiva e tipada para chamar endpoints do Graph.
Escolha a Microsoft. Identity.Web.GraphServiceClient
Os seguintes benefícios fazem com que Microsoft.Identity.Web.GraphServiceClient seja a abordagem recomendada para chamar Microsoft Graph.
- Aquisição automática de tokens: Trata os tokens do utilizador e da aplicação de forma fluida
- Cache de token: Cache incorporada para melhorar o desempenho
- Fluent API: Chamadas de grafo seguras para tipos e compatíveis com IntelliSense
- Consentimento incremental: Solicitar permissões adicionais a pedido
- Múltiplos esquemas de autenticação: Suporte para aplicações web e APIs web
- Tanto a v1.0 como a Beta: Usar endpoints estáveis e de pré-visualização em conjunto
Instalar pacotes necessários
Instale o pacote de integração do Microsoft Graph SDK:
dotnet add package Microsoft.Identity.Web.GraphServiceClient
Para APIs Microsoft Graph Beta:
dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta
Configurar o ASP.NET Core
1. Configurar serviços
Adicione suporte ao Microsoft Graph à sua aplicação:
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. Configurar appsettings.json
Configure opções do Graph no seu ficheiro de configuração:
{
"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"]
}
}
}
Configuração com Código:
builder.Services.AddMicrosoftGraph(options =>
{
builder.Configuration.GetSection("DownstreamApis:MicrosoftGraph").Bind(options);
});
Ou configurar diretamente em código:
builder.Services.AddMicrosoftGraph();
builder.Services.Configure<MicrosoftGraphOptions>(options =>
{
options.BaseUrl = "https://graph.microsoft.com/v1.0";
options.Scopes = new[] { "User.Read", "Mail.Read" };
});
3. Configurar suporte nacional na cloud
Para usar o Microsoft Graph em clouds nacionais, especifique o BaseUrl na sua configuração:
{
"DownstreamApis": {
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.us/v1.0",
"Scopes": ["User.Read"]
}
}
}
Consulte Microsoft Graph deployments para URLs de endpoint.
Usar o GraphServiceClient
Injetar GraphServiceClient
Injetar GraphServiceClient a partir do construtor:
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);
}
}
Use permissões delegadas (tokens de utilizador)
Chame o Graph em nome do utilizador com sessão iniciada com permissões delegadas.
Recuperar o perfil básico do utilizador
Recupere a informação do perfil do utilizador atual no 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
});
}
}
Pedido de consentimento incremental
Solicite escopos adicionais de forma dinâmica quando a sua aplicação os precisar:
[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;
}
}
}
Aplicar opções de consulta
Use as opções de consulta do Graph SDK para filtrar, selecionar e ordenar resultados:
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);
}
Navegar pelos resultados
Tratar dos resultados paginados do Microsoft Graph iterando por cada página:
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);
}
Usar permissões de aplicação (tokens apenas para aplicações)
Chamar Graph com permissões de aplicação quando não for necessário contexto do utilizador.
Grafo de Chamadas com WithAppOnly()
Use o WithAppOnly() método para fazer chamadas Graph com permissões de aplicação.
[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);
}
}
Configurar permissões da aplicação
Especifique um pedido de token de aplicação em appsettings.json:
{
"DownstreamApis": {
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"RequestAppToken": true
}
}
}
Os escopos serão automaticamente definidos para ["https://graph.microsoft.com/.default"].
Configure opções detalhadas apenas para aplicações
Defina opções explícitas de autenticação apenas para aplicação no código.
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);
}
Lidar com múltiplos esquemas de autenticação
Se a sua aplicação usar múltiplos esquemas de autenticação (por exemplo, web app + API), especifique qual o esquema a utilizar:
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);
}
}
Configurar opções detalhadas de esquemas
Defina o esquema de autenticação e os escopos explicitamente no código.
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);
}
Usa tanto os endpoints v1.0 como Beta
Registe e chama tanto o Microsoft Graph v1.0 como o Beta na mesma aplicação.
1. Instalar ambos os pacotes
dotnet add package Microsoft.Identity.Web.GraphServiceClient
dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta
2. Registar ambos os serviços
using Microsoft.Identity.Web;
builder.Services.AddMicrosoftGraph();
builder.Services.AddMicrosoftGraphBeta();
3. Utilizar ambos os clientes
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 });
}
}
Enviar pedidos de lote
Combine múltiplas chamadas Graph num único pedido HTTP para melhorar o desempenho:
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
});
}
Aplicar padrões comuns de grafos
Use estes padrões para realizar operações frequentes do Microsoft Graph na sua aplicação.
Obter o gestor do utilizador
Recupere o manager do utilizador com sessão iniciada no diretório.
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");
}
Obtenha uma foto do utilizador
Descarregue a foto de perfil do utilizador com sessão iniciada como uma stream.
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");
}
}
Enviar e-mail
Envie uma mensagem de email em nome do utilizador iniciado sessão.
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");
}
Criar eventos no calendário
Crie um novo evento no calendário com participantes para o utilizador autenticado.
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);
}
Pesquisar utilizadores
Procure utilizadores no diretório por nome de exibição ou endereço de email.
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);
}
Implementar suporte OWIN
Para aplicações ASP.NET que utilizam OWIN, configurar a fábrica de aquisição de tokens e registar os serviços do 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. API de chamadas a partir dos controladores
Recupera uma instância GraphServiceClient no teu controlador e chama-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);
}
}
Migrar do Microsoft.Identity.Web.MicrosoftGraph 2.x
Se estiver a migrar do pacote mais antigo Microsoft.Identity.Web.MicrosoftGraph (SDK 4.x), analise as seguintes alterações principais:
1. Remover o pacote antigo e adicionar um novo
dotnet remove package Microsoft.Identity.Web.MicrosoftGraph
dotnet add package Microsoft.Identity.Web.GraphServiceClient
2. Atualizar chamadas de método
O .Request() método foi removido no SDK 5.x:
Antes (SDK 4.x):
var user = await _graphClient.Me.Request().GetAsync();
var messages = await _graphClient.Me.Messages
.Request()
.WithScopes("Mail.Read")
.GetAsync();
Depois (SDK 5.x):
var user = await _graphClient.Me.GetAsync();
var messages = await _graphClient.Me.Messages
.GetAsync(r => r.Options.WithScopes("Mail.Read"));
3. Atualização da localização do 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. Atualização da localização WithAppOnly()
Before:
var apps = await _graphClient.Applications
.Request()
.WithAppOnly()
.GetAsync();
After:
var apps = await _graphClient.Applications
.GetAsync(r => r.Options.WithAppOnly());
5. Atualizar a localização da 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));
Consulte Microsoft Graph .NET SDK v5 changelog para detalhes completos da migração.
Lidar com erros
Handle ServiceException
Captura ODataError e MicrosoftIdentityWebChallengeUserException para lidar de forma elegante com falhas da 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");
}
}
Siga as melhores práticas
1. Solicitar parâmetros mínimos
Solicita apenas os âmbitos que precisas:
// 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" };
2. Utilizar consentimento incremental
Solicite âmbitos adicionais apenas quando necessário:
// Sign-in: Only User.Read
// Later, when accessing mail:
var messages = await _graphClient.Me.Messages
.GetAsync(r => r.Options.WithScopes("Mail.Read"));
3. Cliente do GraphServiceCache
O GraphServiceClient é seguro para reutilizar. Registe como singleton ou injeta a partir do DI.
4. Usar select para reduzir o tamanho da resposta
// 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" });
Resolver problemas comuns
Resolver "Privilégios insuficientes para completar a operação"
Causa: A aplicação não tem permissões Graph obrigatórias.
Solução:
- Adicionar as permissões necessárias da API no registo da aplicação
- Consentimento do administrador é necessário para permissões da aplicação
- Consentimento do utilizador necessário para permissões delegadas
Resolver "AADSTS65001: O utilizador ou administrador não consentiu"
Causa: O utilizador não consentiu nas permissões solicitadas.
Solução: Use o consentimento incremental com .WithScopes() para desencadear o fluxo de consentimento.
Resolver erros da foto 404
Causa: O utilizador não tem foto de perfil.
Solução: Lidar com o 404 com elegância e fornecer avatar padrão.
Resolver falhas de pedidos em lote
Causa: Pedidos individuais em lote podem falhar de forma independente.
Solução: Verifique cada resposta em lote para erros:
var userResponse = await batchResponse.GetResponseByIdAsync<User>(userRequestId);
if (userResponse == null)
{
// Handle individual request failure
}
Conteúdo relacionado
- A Documentação do Microsoft Graph
- Guia de Migração do Graph SDK v5
- Visão Geral sobre o Uso de APIs Downstream
- Chamada a partir de Aplicações Web
- Chamadas a partir de APIs Web
Próximos Passos: Aprenda sobre calling SDKs do Azure ou APIs personalizadas.