Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Aplica-se a: Locatários da força de trabalho
Locatários externos (saiba mais)
Esta série de tutoriais demonstra como proteger uma API Web do ASP.NET Core com a plataforma de identidade da Microsoft para limitar seu acesso apenas a usuários autorizados e aplicativos cliente. A API Web criada usa permissões delegadas (escopos) e permissões de aplicativo (funções de aplicativo).
Neste tutorial, você:
- Criar uma API Web do ASP.NET Core
- Configurar a API da web para usar as informações de registro do aplicativo Microsoft Entra
- Proteger os pontos de extremidade da API Web
- Execute a API Web para garantir que ela esteja escutando solicitações HTTP
Pré-requisitos
- Caso ainda não tenha feito isso, conclua as etapas no Início Rápido: chamar uma API Web protegida pela plataforma de identidade da Microsoft. Você não precisa clonar e executar o exemplo de código, mas verifique se tem o seguinte:
- Os detalhes de registro do aplicativo da API Web do Centro de administração do Microsoft Entra, incluindo a ID do cliente e a ID do locatário.
- ToDoList.Read e ToDoList.ReadWrite como as permissões delegadas (escopos) expostas pela API Web
- ToDoList.Read.All e ToDoList.ReadWrite.All como as permissões de aplicativo (funções de aplicativo) expostas pela API Web
- SDK do .NET 8.0 ou posterior.
- Visual Studio Code ou qualquer outro editor de código.
Criar um novo projeto de API Web do ASP.NET Core
Para criar um projeto mínimo de API Web do ASP.NET Core, siga estas etapas:
Abra seu terminal no Visual Studio Code ou em qualquer outro editor de código e navegue até o diretório onde você deseja criar seu projeto.
Execute os comandos a seguir na CLI do .NET ou em qualquer outra ferramenta de linha de comando.
dotnet new web -o TodoListApi cd TodoListApi
Selecione Sim quando uma caixa de diálogo perguntar se você deseja confiar nos autores.
Selecione Sim quando uma caixa de diálogo perguntar se você deseja adicionar ativos necessários ao projeto.
Instalar pacotes necessários
Para criar, proteger e testar a API Web do ASP.NET Core, você precisa instalar os seguintes pacotes:
Microsoft.EntityFrameworkCore.InMemory
- Um pacote que permite que você use o Entity Framework Core com um banco de dados na memória. Ele é útil para fins de teste, mas não foi projetado para uso em produção.Microsoft.Identity.Web
- um conjunto de bibliotecas do ASP.NET Core que simplificam a adição de suporte de autenticação e autorização a aplicativos Web e APIs Web que se integram à plataforma de identidade da Microsoft.
Para instalar o pacote, use:
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
Configurar detalhes de registro do aplicativo
Abra o arquivo appsettings.json na pasta do aplicativo e adicione os detalhes de registro do aplicativo que você registrou depois de registrar a API Web.
{
"AzureAd": {
"Instance": "Enter_the_Authority_URL_Here",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here"
},
"Logging": {...},
"AllowedHosts": "*"
}
Substitua os seguintes espaços reservados, conforme mostrado a seguir:
- Substitua
Enter_the_Application_Id_Here
pela ID do aplicativo (cliente). - Substitua
Enter_the_Tenant_Id_Here
pela ID do seu Diretório (locatário). - Substitua
Enter_the_Authority_URL_Here
pela URL de Autoridade, conforme explicado na próxima seção.
URL de autoridade para seu aplicativo
A URL de autoridade especifica o diretório do qual a MSAL (Biblioteca de Autenticação da Microsoft) pode solicitar tokens. Você o cria de forma diferente na força de trabalho e nos locatários externos, conforme mostrado:
//Instance for workforce tenant
Instance: "https://login.microsoftonline.com/"
Usar domínio de URL personalizado (opcional)
Não há suporte para os domínios da URL personalizados nos locatários da força de trabalho.
Adicionar permissões
Todas as APIs devem publicar ao menos um escopo, também chamado de permissão delegada, para que os aplicativos clientes obtenham um token de acesso para um usuário com sucesso. As APIs também devem publicar no mínimo uma função de aplicativo, também chamada de permissões de aplicativo, para que os aplicativos cliente obtenham um token de acesso em nome próprio, ou seja, quando não estão autenticando um usuário.
Especificaremos essas permissões no arquivo appsettings.json. Neste tutorial, você registrou as seguintes permissões delegadas e de aplicativo:
- Permissões delegadas:ToDoList.Read e ToDoList.ReadWrite.
- Permissões de aplicativos:ToDoList.Read.All e ToDoList.ReadWrite.All.
Quando um usuário ou aplicativo cliente chama a API Web, somente os clientes com esses escopos ou permissões são autorizados a acessar o ponto de extremidade protegido.
{
"AzureAd": {
"Instance": "Enter_the_Authority_URL_Here",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
"Scopes": {
"Read": ["ToDoList.Read", "ToDoList.ReadWrite"],
"Write": ["ToDoList.ReadWrite"]
},
"AppPermissions": {
"Read": ["ToDoList.Read.All", "ToDoList.ReadWrite.All"],
"Write": ["ToDoList.ReadWrite.All"]
}
},
"Logging": {...},
"AllowedHosts": "*"
}
Implementar autenticação e autorização na API
Para configurar a autenticação e a autorização, abra o program.cs
arquivo e substitua seu conteúdo pelos seguintes snippets de código:
Adicionar um esquema de autenticação
Nesta API, usamos o esquema de portador JWT (Token Web JSON) como o mecanismo de autenticação padrão. Utilize o método AddAuthentication
para registrar o esquema de portador JWT.
// Add required packages to your imports
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add an authentication scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);
Criar o modelo do aplicativo
Na pasta raiz do projeto, crie uma pasta chamada Modelos. Navegue até a pasta Modelos e crie um arquivo nomeado ToDo.cs
e adicione o código a seguir.
using System;
namespace ToDoListAPI.Models;
public class ToDo
{
public int Id { get; set; }
public Guid Owner { get; set; }
public string Description { get; set; } = string.Empty;
}
O código anterior cria um modelo chamado ToDo. Esse modelo representa os dados que o aplicativo gerencia.
Adicionar um contexto de banco de dados
Em seguida, definimos uma classe de contexto de banco de dados, que coordena a funcionalidade do Entity Framework para um modelo de dados. Essa classe herda da classe Microsoft.EntityFrameworkCore.DbContext que gerencia interações entre o aplicativo e o banco de dados. Para adicionar o contexto do banco de dados, siga estas etapas:
Crie uma pasta chamada DbContext na pasta raiz do projeto.
Navegue até a pasta DbContext e crie um arquivo nomeado
ToDoContext.cs
e adicione o seguinte código:using Microsoft.EntityFrameworkCore; using ToDoListAPI.Models; namespace ToDoListAPI.Context; public class ToDoContext : DbContext { public ToDoContext(DbContextOptions<ToDoContext> options) : base(options) { } public DbSet<ToDo> ToDos { get; set; } }
Abra o arquivo Program.cs na pasta raiz do projeto e atualize-o com o seguinte código:
// Add the following to your imports using ToDoListAPI.Context; using Microsoft.EntityFrameworkCore; //Register ToDoContext as a service in the application builder.Services.AddDbContext<ToDoContext>(opt => opt.UseInMemoryDatabase("ToDos"));
No snippet de código anterior, registramos o Contexto de BD como um serviço com escopo no provedor de serviços do aplicativo ASP.NET Core (também conhecido como contêiner de injeção de dependência). Você também configura a ToDoContext
classe para usar um banco de dados na memória para a API de Lista de ToDo.
Configurar um controlador
Normalmente, os controladores implementam ações CRUD (Criar, Ler, Atualizar e Excluir) para gerenciar recursos. Como este tutorial se concentra mais na proteção dos pontos de extremidade da API, implementamos apenas dois itens de ação no controlador. Uma ação Ler tudo para recuperar todos os itens de Tarefas Pendentes e uma ação Criar para adicionar um novo item de Tarefas Pendentes. Siga estas etapas para adicionar um controlador ao seu projeto:
Navegue até a pasta raiz do projeto e crie uma pasta chamada Controladores.
Crie um arquivo chamado
ToDoListController.cs
dentro da pasta Controladores e adicione o seguinte código padrão:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
using ToDoListAPI.Models;
using ToDoListAPI.Context;
namespace ToDoListAPI.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ToDoListController : ControllerBase
{
private readonly ToDoContext _toDoContext;
public ToDoListController(ToDoContext toDoContext)
{
_toDoContext = toDoContext;
}
[HttpGet()]
[RequiredScopeOrAppPermission()]
public async Task<IActionResult> GetAsync(){...}
[HttpPost]
[RequiredScopeOrAppPermission()]
public async Task<IActionResult> PostAsync([FromBody] ToDo toDo){...}
private bool RequestCanAccessToDo(Guid userId){...}
private Guid GetUserId(){...}
private bool IsAppMakingRequest(){...}
}
Adicionar código ao controlador
Esta seção explica como adicionar código ao controlador que foi estruturado na seção descrita anteriormente. O foco aqui é proteger a API, não compila-la.
Importe os pacotes necessários: O
Microsoft.Identity.Web
pacote é um wrapper em torno de MSAL.NET que nos ajuda a lidar facilmente com a lógica de autenticação, como lidar com a validação de token. Para garantir que nossos pontos de extremidade exijam autorização, usamos o pacote deMicrosoft.AspNetCore.Authorization
embutido.Como concedemos permissões para que esta API possa ser chamada tanto usando permissões delegadas em nome do usuário quanto permissões de aplicativo, onde o cliente faz a chamada em seu próprio nome e não em nome do usuário, é importante saber se a chamada está sendo feita pelo aplicativo em seu próprio nome. A maneira mais fácil de fazer isso é descobrir se o token de acesso contém a
idtyp
declaração opcional. Essa declaraçãoidtyp
é a maneira mais fácil para uma API determinar se um token é um token de aplicativo ou um token de aplicativo + usuário. Recomendamos habilitar a declaração opcionalidtyp
.Se a declaração
idtyp
não estiver habilitada, você poderá usar as declaraçõesroles
escp
para determinar se o token de acesso é um token de aplicativo ou um token de aplicativo + usuário. Um token de acesso emitido pelo Microsoft Entra ID tem pelo menos uma das duas declarações. Os tokens de acesso emitidos para um usuário têm a declaraçãoscp
. Os tokens de acesso emitidos para um aplicativo têm a declaraçãoroles
. Os tokens de acesso que contêm ambas as declarações são emitidos apenas para os usuários, em que a declaraçãoscp
designa as permissões delegadas, enquanto a declaraçãoroles
designa a função do usuário. Os tokens de acesso que não possuem nenhuma delas não devem ser aceitos.private bool IsAppMakingRequest() { if (HttpContext.User.Claims.Any(c => c.Type == "idtyp")) { return HttpContext.User.Claims.Any(c => c.Type == "idtyp" && c.Value == "app"); } else { return HttpContext.User.Claims.Any(c => c.Type == "roles") && !HttpContext.User.Claims.Any(c => c.Type == "scp"); } }
Adicione uma função auxiliar que determinará se a solicitação que está sendo feita contém permissões suficientes para executar a ação pretendida. Verificar se é o próprio aplicativo que está fazendo a solicitação em seu próprio nome ou se o aplicativo está fazendo a chamada em nome de um usuário que é proprietário do recurso fornecido, validando a ID do usuário.
private bool RequestCanAccessToDo(Guid userId) { return IsAppMakingRequest() || (userId == GetUserId()); } private Guid GetUserId() { Guid userId; if (!Guid.TryParse(HttpContext.User.GetObjectId(), out userId)) { throw new Exception("User ID is not valid."); } return userId; }
Insira suas definições de permissão para proteger rotas. Proteja sua API adicionando o atributo
[Authorize]
à classe de controlador. Isso garante que as ações do controlador possam ser chamadas somente se a API for chamada com uma identidade autorizada. As definições de permissão definem quais tipos de permissões são necessárias para executar essas ações.[Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController: ControllerBase{...}
Adicione permissões nos endpoints GET e POST. Faça isso usando o método RequiredScopeOrAppPermission que faz parte do namespace Microsoft.Identity.Web.Resource. Em seguida, passe escopos e permissões para esse método por meio dos atributos RequiredScopesConfigurationKey e RequiredAppPermissionsConfigurationKey.
[HttpGet] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Read", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Read" )] public async Task<IActionResult> GetAsync() { var toDos = await _toDoContext.ToDos! .Where(td => RequestCanAccessToDo(td.Owner)) .ToListAsync(); return Ok(toDos); } [HttpPost] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Write", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Write" )] public async Task<IActionResult> PostAsync([FromBody] ToDo toDo) { // Only let applications with global to-do access set the user ID or to-do's var ownerIdOfTodo = IsAppMakingRequest() ? toDo.Owner : GetUserId(); var newToDo = new ToDo() { Owner = ownerIdOfTodo, Description = toDo.Description }; await _toDoContext.ToDos!.AddAsync(newToDo); await _toDoContext.SaveChangesAsync(); return Created($"/todo/{newToDo!.Id}", newToDo); }
Configurar o middleware da API para usar o controlador
Em seguida, configuramos o aplicativo para reconhecer e usar controladores para lidar com solicitações HTTP. Abra o program.cs
arquivo e adicione o código a seguir para registrar os serviços do controlador no contêiner de injeção de dependência.
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
No snippet de código anterior, o AddControllers()
método prepara o aplicativo para usar controladores registrando os serviços necessários enquanto MapControllers()
mapeia as rotas do controlador para lidar com solicitações HTTP de entrada.
Executar sua API
Execute sua API para garantir que ela esteja em execução sem erros usando o comando dotnet run
. Se você pretende usar o protocolo HTTPS mesmo durante o teste, precisará confiar no certificado de desenvolvimento do .NET.
Inicie o aplicativo digitando o seguinte no terminal:
dotnet run
Uma saída semelhante à seguinte deve ser exibida no terminal, o que confirma que o aplicativo está em execução no
http://localhost:{port}
e escutando as solicitações.Building... info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:{port} info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. ...
A página http://localhost:{host}
da Web exibe uma saída semelhante à imagem a seguir. Isso ocorre porque a API está sendo chamada sem autenticação. Para fazer uma chamada autorizada, consulte as próximas etapas para obter diretrizes sobre como acessar uma API Web protegida.
Para obter um exemplo completo desse código de API, consulte o arquivo de exemplos.
Próximas etapas
Parte 2: Chamar a API Web protegida do ASP.NET Core