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.
Neste artigo, você implementa a autorização em ASP.NET Core APIs Web usando Microsoft. Identity.Web. Você validará escopos (permissões delegadas) e permissões de aplicativo para controlar o acesso aos recursos protegidos. Os exemplos usam Microsoft Entra ID como o provedor de identidade.
Entender os conceitos de autorização
Esta seção aborda as principais diferenças entre autenticação e autorização e descreve o que Microsoft. Identity.Web valida em tokens de acesso.
Autenticação versus autorização
| Conceito | Propósito | Resultado |
|---|---|---|
| Autenticação | Verificar identidade | 401 Não autorizado em caso de falha |
| Autorização | Verificar permissões | 403 Proibido se insuficiente |
O que é validado
Quando uma API Web recebe um token de acesso, Microsoft. Identity.Web valida:
- Assinatura de token - É de uma autoridade confiável?
- Audience do token – Ele é destinado a esta API?
- Expiração do token – Ainda é válido?
- Escopos/Funções - O aplicativo cliente e o assunto (usuário) têm as permissões certas?
Este guia se concentra em #4 – validando escopos e permissões de aplicativo.
Escopos (permissões delegadas)
Os escopos se aplicam quando um usuário delega permissão a um aplicativo para agir em seu nome (por exemplo, uma API Web chamada em nome de um usuário conectado).
| Detalhes | Valor |
|---|---|
| Declaração de token |
scp ou scope (aplicativo cliente); roles (usuário) |
| Valores de exemplo |
"access_as_user"
"User.Read", "Files.ReadWrite" |
Permissões de aplicativo (permissões de aplicativo)
As permissões de aplicativo se aplicam quando um aplicativo chama a API Web como ela mesma sem contexto de usuário, como um daemon ou um serviço em segundo plano usando credenciais de cliente.
| Detalhes | Valor |
|---|---|
| Declaração de token | roles |
| Valores de exemplo |
"Mail.Read.All", "User.Read.All" |
Validar escopos com RequiredScope
O RequiredScope atributo verifica se o token de acesso contém pelo menos um dos escopos especificados. Use esse atributo quando a API atender apenas às solicitações delegadas pelo usuário.
Configurar a validação de escopo
Siga estas etapas para habilitar a validação de escopo em sua API.
1. Habilitar a autorização em sua API:
Adicione serviços de autenticação e autorização ao pipeline de aplicativos:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(); // Required for authorization
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization(); // Must be after UseAuthentication
app.MapControllers();
app.Run();
2. Proteger controladores ou ações:
Aplique os atributos [Authorize] e [RequiredScope] ao seu controlador ou a ações individuais:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Identity.Web.Resource;
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
[HttpGet]
public IActionResult GetTodos()
{
// Only accessible if token has "access_as_user" scope
return Ok(new[] { "Todo 1", "Todo 2" });
}
}
Aplicar padrões de escopo
Escolha o padrão que melhor se ajusta à maneira como você gerencia escopos em seu aplicativo.
Padrão 1: escopos definidos em código
Use esse padrão quando os escopos forem fixos e conhecidos no momento do desenvolvimento.
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
// All actions require "access_as_user" scope
}
Para aceitar qualquer um dos vários escopos, liste-os como parâmetros:
[Authorize]
[RequiredScope("read", "write", "admin")]
public class TodoListController : ControllerBase
{
// Token must have "read" OR "write" OR "admin"
}
Padrão 2: Escopos a partir da configuração
Use esse padrão quando os escopos devem ser configuráveis por ambiente. Defina os escopos no arquivo de configuração:
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user read write"
}
}
Faça referência à chave de configuração em seu controlador:
[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : ControllerBase
{
// Scopes read from configuration
}
Essa abordagem permite alterar escopos sem recompilar.
Padrão 3: escopos no nível da ação
Use esse padrão quando ações diferentes exigirem permissões diferentes. Aplique [RequiredScope] aos métodos de ação individuais:
[Authorize]
public class TodoListController : ControllerBase
{
[HttpGet]
[RequiredScope("read")]
public IActionResult GetTodos()
{
return Ok(todos);
}
[HttpPost]
[RequiredScope("write")]
public IActionResult CreateTodo([FromBody] Todo todo)
{
// Only tokens with "write" scope can create
return CreatedAtAction(nameof(GetTodos), todo);
}
[HttpDelete("{id}")]
[RequiredScope("admin")]
public IActionResult DeleteTodo(int id)
{
// Only tokens with "admin" scope can delete
return NoContent();
}
}
Entender o fluxo de validação
Quando uma solicitação chega, o middleware a processa na seguinte ordem:
- O middleware de autenticação do ASP.NET Core valida o token.
-
RequiredScopeverificação de atributos para a reivindicaçãoscpouscope - Se o token contiver pelo menos um escopo correspondente, a solicitação continuará.
- Se nenhum escopo correspondente for encontrado, a API retornará uma resposta 403 Proibida.
O exemplo a seguir mostra uma resposta de erro típica:
{
"error": "insufficient_scope",
"error_description": "The token does not have the required scope 'access_as_user'."
}
Validar permissões de aplicativo com RequiredScopeOrAppPermission
O RequiredScopeOrAppPermission atributo valida escopos (delegados) ou permissões de aplicativo (aplicativo). Use esse atributo quando a API atender a aplicativos com delegação de usuário e aplicativos daemon/serviço do mesmo ponto de extremidade.
Se a API atender apenas às solicitações delegadas pelo usuário, use RequiredScope em vez disso.
Configurar a validação das permissões de escopo ou de aplicativo
Aplique o atributo para aceitar qualquer tipo de token:
using Microsoft.Identity.Web.Resource;
[Authorize]
[RequiredScopeOrAppPermission(
AcceptedScope = new[] { "access_as_user" },
AcceptedAppPermission = new[] { "TodoList.ReadWrite.All" }
)]
public class TodoListController : ControllerBase
{
[HttpGet]
public IActionResult GetTodos()
{
// Accessible with EITHER:
// - User-delegated token with "access_as_user" scope, OR
// - App-only token with "TodoList.ReadWrite.All" app permission
return Ok(todos);
}
}
Configurar permissões de aplicativo a partir de configurações
Armazene escopos e permissões de aplicativo na configuração para alterá-los sem recompilar.
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user",
"AppPermissions": "TodoList.ReadWrite.All TodoList.Admin"
}
}
Faça referência às chaves de configuração no controlador:
[Authorize]
[RequiredScopeOrAppPermission(
RequiredScopesConfigurationKey = "AzureAd:Scopes",
RequiredAppPermissionsConfigurationKey = "AzureAd:AppPermissions"
)]
public class TodoListController : ControllerBase
{
// Scopes and app permissions from configuration
}
Comparar diferenças de reivindicações de token
A tabela a seguir mostra como as declarações diferem entre tokens delegados pelo usuário e somente de aplicativo:
| Tipo de token | Reclamação | Exemplo de valor |
|---|---|---|
| Atribuído pelo usuário |
scp ou scope |
"access_as_user User.Read" |
| Somente aplicativo | roles |
["TodoList.ReadWrite.All"] |
O exemplo a seguir mostra um token delegado pelo usuário:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"scp": "access_as_user",
"sub": "user-object-id",
...
}
O exemplo a seguir mostra um token somente de aplicativo:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"roles": ["TodoList.ReadWrite.All"],
"sub": "app-object-id",
...
}
Criar políticas de autorização
Para cenários complexos de autorização, use ASP.NET Core políticas de autorização. As políticas permitem centralizar regras, combinar vários requisitos e gravar a lógica de autorização testável.
| Benefit | Descrição |
|---|---|
| Lógica centralizada | Definir regras de autorização uma vez, reutilizar em todos os lugares |
| Componível | Combinar vários requisitos (escopos + afirmações + lógica personalizada) |
| Testável | Lógica de autorização mais fácil de testar de forma unitária. |
| Flexível | Requisitos personalizados que excedem o escopo de validação |
Padrão 1: Definir uma política com RequireScope
Defina políticas nomeadas que exijam escopos específicos e, em seguida, faça referência a elas em seus controladores:
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("TodoReadPolicy", policyBuilder =>
{
policyBuilder.RequireScope("read", "access_as_user");
});
options.AddPolicy("TodoWritePolicy", policyBuilder =>
{
policyBuilder.RequireScope("write", "admin");
});
});
var app = builder.Build();
Aplique as políticas às ações do controlador:
[Authorize]
public class TodoListController : ControllerBase
{
[HttpGet]
[Authorize(Policy = "TodoReadPolicy")]
public IActionResult GetTodos()
{
return Ok(todos);
}
[HttpPost]
[Authorize(Policy = "TodoWritePolicy")]
public IActionResult CreateTodo([FromBody] Todo todo)
{
return CreatedAtAction(nameof(GetTodos), todo);
}
}
Padrão 2: Definir uma política com ScopeAuthorizationRequirement
Use ScopeAuthorizationRequirement para requisitos de escopo mais explícitos:
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CustomPolicy", policyBuilder =>
{
policyBuilder.AddRequirements(
new ScopeAuthorizationRequirement(new[] { "access_as_user" })
);
});
});
Padrão 3: Definir uma política padrão
Defina uma política padrão que se aplique a todos os [Authorize] atributos automaticamente:
builder.Services.AddAuthorization(options =>
{
var defaultPolicy = new AuthorizationPolicyBuilder()
.RequireScope("access_as_user")
.Build();
options.DefaultPolicy = defaultPolicy;
});
Cada [Authorize] atributo agora requer o access_as_user escopo:
[Authorize] // Automatically requires "access_as_user" scope
public class TodoListController : ControllerBase
{
// All actions protected by default policy
}
Padrão 4: Combinar vários requisitos
Combine os requisitos de escopo, função e autenticação em uma única política:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policyBuilder =>
{
policyBuilder.RequireScope("admin");
policyBuilder.RequireRole("Admin"); // Also check role claim
policyBuilder.RequireAuthenticatedUser();
});
});
Padrão 5: criar uma política com base na configuração
Carregue escopos da configuração para manter as políticas específicas do ambiente:
var requiredScopes = builder.Configuration["AzureAd:Scopes"]?.Split(' ');
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ApiAccessPolicy", policyBuilder =>
{
if (requiredScopes != null)
{
policyBuilder.RequireScope(requiredScopes);
}
});
});
Filtrar solicitações por locatário
Restrinja o acesso à API a tokens de locatários Microsoft Entra específicos. Isso é útil quando sua API multilocatário só deve aceitar solicitações de locatários aprovados do cliente.
Restringir o acesso a locatários permitidos
Defina uma política que verifica a declaração de ID do locatário em relação a uma lista de permissões:
builder.Services.AddAuthorization(options =>
{
string[] allowedTenants =
{
"14c2f153-90a7-4689-9db7-9543bf084dad", // Contoso tenant
"af8cc1a0-d2aa-4ca7-b829-00d361edb652", // Fabrikam tenant
"979f4440-75dc-4664-b2e1-2cafa0ac67d1" // Northwind tenant
};
options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
{
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants
);
});
// Apply to all endpoints by default
options.DefaultPolicy = options.GetPolicy("AllowedTenantsOnly");
});
Configurar a filtragem de locatários nas configurações
Armazene IDs de locatário permitidas na configuração para gerenciá-las sem alterações de código.
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "your-api-client-id",
"AllowedTenants": [
"14c2f153-90a7-4689-9db7-9543bf084dad",
"af8cc1a0-d2aa-4ca7-b829-00d361edb652"
]
}
}
Leia a lista de locatários e crie a política na inicialização:
var allowedTenants = builder.Configuration.GetSection("AzureAd:AllowedTenants")
.Get<string[]>();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
{
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants ?? Array.Empty<string>()
);
});
});
Combinar escopos com filtragem de cliente
Crie uma política que exija um escopo válido e um locatário aprovado:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("SecureApiAccess", policyBuilder =>
{
// Require specific scope
policyBuilder.RequireScope("access_as_user");
// AND require specific tenant
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants
);
});
});
Seguir as práticas recomendadas
Aplique essas recomendações para criar uma lógica de autorização segura e mantenedível.
O que fazer
1. Sempre associe [Authorize] com a validação de escopo:
[Authorize] // Authentication
[RequiredScope("access_as_user")] // Authorization
public class MyController : ControllerBase { }
2. Use a configuração para escopos específicos do ambiente:
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
3. Aplicar privilégios mínimos:
[HttpGet]
[RequiredScope("read")] // Only read permission needed
[HttpPost]
[RequiredScope("write")] // Write permission for modifications
4. Use políticas para autorização complexa:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireScope("admin");
policy.RequireClaim("department", "IT");
});
});
5. Habilitar respostas de erro detalhadas no desenvolvimento:
if (builder.Environment.IsDevelopment())
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
}
O que não fazer
1. Não ignore [Authorize] ao usar RequiredScope:
// Wrong - RequiredScope won't work without [Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }
// Correct
[Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }
2. Não codificar fixamente IDs de inquilino na produção:
// Wrong
policyBuilder.RequireClaim("tid", "14c2f153-90a7-4689-9db7-9543bf084dad");
// Better - use configuration
var tenants = Configuration.GetSection("AllowedTenants").Get<string[]>();
policyBuilder.RequireClaim("tid", tenants);
3. Não confunda escopos com funções:
// Wrong - This checks roles claim, not scopes
[RequiredScope("Admin")] // "Admin" is typically a role, not a scope
// Correct
[RequiredScope("access_as_user")] // Scope
[Authorize(Roles = "Admin")] // Role
4. Não exponha informações confidenciais de escopo em mensagens de erro de produção:
Configure os níveis de log apropriados e o tratamento de erros para ambientes de produção.
Solucionar problemas de autorização
Use as diretrizes a seguir para diagnosticar problemas comuns de autorização.
403 Proibido – escopo ausente
Erro: A API retorna 403 mesmo com um token válido.
Diagnóstico:
- Decodificar o token em jwt.ms.
- Verifique
scpouscopedeclaração. - Verifique se o valor corresponde ao atributo
RequiredScope.
Solution:
- Verifique se o aplicativo cliente solicita o escopo correto ao adquirir o token.
- Verifique se o escopo está exposto no registro do aplicativo de API no Microsoft Entra.
- Conceda consentimento do administrador, se necessário.
RequiredScope não está funcionando
Sintoma: O atributo parece ser ignorado.
Verificar:
- Você adicionou o
[Authorize]atributo? - Depois
app.UseAuthorization(), éapp.UseAuthentication()chamado? - Está
services.AddAuthorization()registrado?
Chave de configuração não encontrada
Erro: A validação de escopo falha silenciosamente.
Verificar:
{
"AzureAd": {
"Scopes": "access_as_user" // Matches RequiredScopesConfigurationKey
}
}
Verifique se o caminho de configuração corresponde exatamente.