Visão geral da autenticação do ASP.NET Core

Por Mike Rousos

Autenticação é o processo de determinar a identity de um usuário. Autorização é o processo de determinar se um usuário tem acesso a um recurso. No ASP.NET Core, a autenticação é tratada pelo serviço de autenticação, IAuthenticationService, que é usado pelo middleware de autenticação. O serviço de autenticação usa manipuladores de autenticação registrados para realizar ações relacionadas à autenticação. Exemplos de ações relacionadas à autenticação incluem:

  • Autenticar um usuário.
  • Responder quando um usuário não autenticado tenta acessar um recurso restrito.

Os manipuladores de autenticação registrados e suas opções de configuração são chamados de "esquemas".

Os esquemas de autenticação são especificados registrando serviços de autenticação em Program.cs:

Por exemplo, o seguinte código registra serviços de autenticação e manipuladores para cookie e esquemas de autenticação de portador JWT:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme,
        options => builder.Configuration.Bind("JwtSettings", options))
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
        options => builder.Configuration.Bind("CookieSettings", options));

O parâmetro AddAuthentication JwtBearerDefaults.AuthenticationScheme é o nome do esquema a ser usado por padrão quando um esquema específico não é solicitado.

Se vários esquemas forem usados, políticas de autorização (ou atributos de autorização) poderão especificar o esquema de autenticação (ou esquemas) de que dependem para autenticar o usuário. No exemplo acima, o esquema de autenticação cookie pode ser usado especificando seu nome (CookieAuthenticationDefaults.AuthenticationScheme por padrão, embora um nome diferente possa ser fornecido ao chamar AddCookie).

Em alguns casos, a chamada para AddAuthentication é feita automaticamente por outros métodos de extensão. Por exemplo, ao usar o ASP.NET CoreIdentity, AddAuthentication é chamado internamente.

O middleware de Autenticação é adicionado em Program.cs chamando UseAuthentication. Chamar UseAuthentication registra o middleware que usa os esquemas de autenticação registrado anteriormente. Chame UseAuthentication antes de qualquer middleware que dependa de usuários serem autenticados.

Conceitos de autenticação

A autenticação é responsável por fornecer o ClaimsPrincipal autorização para tomar decisões de permissão. Há várias abordagens de esquema de autenticação para selecionar qual manipulador de autenticação é responsável por gerar o conjunto correto de declarações:

Quando houver apenas um único esquema de autenticação registrado, ele se torna o esquema padrão. Se vários esquemas forem registrados e o esquema padrão não for especificado, um esquema deverá ser especificado no atributo de autorização, caso contrário, o seguinte erro será gerado:

InvalidOperationException: nenhum authenticationScheme foi especificado e não foi encontrado nenhum DefaultAuthenticateScheme. Os esquemas padrão podem ser definidos usando AddAuthentication(string defaultScheme) ou AddAuthentication(Action<AuthenticationOptions> configureOptions).

DefaultScheme

Quando houver apenas um único esquema de autenticação registrado, o esquema de autenticação única:

Para desabilitar automaticamente o uso do esquema de autenticação única como o DefaultScheme, chame AppContext.SetSwitch("Microsoft.AspNetCore.Authentication.SuppressAutoDefaultScheme").

Esquema de autenticação

O esquema de autenticação pode selecionar qual manipulador de autenticação é responsável por gerar o conjunto correto de declarações. Para obter mais informações, consulte Autorizar com um esquema específico.

Um esquema de autenticação é um nome que corresponde a:

  • Um manipulador de autenticação.
  • Opções para configurar essa instância específica do manipulador.

Os esquemas são úteis como um mecanismo para fazer referência à autenticação, ao desafio e à proibição de comportamentos do manipulador associado. Por exemplo, uma política de autorização pode usar nomes de esquema para especificar qual esquema de autenticação (ou esquemas) deve ser usado para autenticar o usuário. Ao configurar a autenticação, é comum especificar o esquema de autenticação padrão. O esquema padrão é usado, a menos que um recurso solicite um esquema específico. Também é possível:

  • Especificar diferentes esquemas padrão a serem usados para autenticar, desafiar e proibir ações.
  • Combinar vários esquemas em um usando esquemas de política.

Manipulador de autenticação

Um manipulador de autenticação:

Com base na configuração do esquema de autenticação e no contexto da solicitação de entrada, os manipuladores de autenticação:

  • Construa objetos AuthenticationTicket que representem a identity do usuário se a autenticação for bem-sucedida.
  • Retornará "nenhum resultado" ou "falha" se a autenticação não for bem-sucedida.
  • Tenha métodos para desafiar e proibir ações para quando os usuários tentarem acessar recursos:
    • Que eles não estão autorizados a acessar (proibir).
    • Quando eles não estão autenticados (desafio).

RemoteAuthenticationHandler<TOptions> versus AuthenticationHandler<TOptions>

RemoteAuthenticationHandler<TOptions> é a classe para autenticação que requer uma etapa de autenticação remota. Quando a etapa de autenticação remota for concluída, o manipulador retornará ao CallbackPath definido pelo manipulador. O manipulador conclui a etapa de autenticação usando as informações passadas para o caminho do retorno de chamada HandleRemoteAuthenticateAsync. OAuth 2.0 e OIDC usam esse padrão. JWT e cookies não, pois podem usar diretamente o cabeçalho do portador e cookie para autenticar. O provedor hospedado remotamente neste caso:

  • É o provedor de autenticação.
  • Exemplos incluem o Facebook, o Twitter, o Google, o Microsoft e qualquer outro provedor de OIDC que manipula a autenticação de usuários usando o mecanismo de manipuladores.

Authenticate

A ação de autenticação de um esquema de autenticação é responsável por construir a identity do usuário com base no contexto de solicitação. Ela retorna um AuthenticateResult que indica se a autenticação foi bem-sucedida e, nesse caso, a identity do usuário em um tíquete de autenticação. Consulte AuthenticateAsync. Exemplos de autenticação incluem:

  • Um esquema de autenticação cookie que constrói a identity do usuário com base em cookies.
  • Um esquema de portador JWT que desserializa e valida um token de portador JWT para construir a identity do usuário.

Desafio

Um desafio de autenticação é invocado pela Autorização quando um usuário não autenticado solicita um ponto de extremidade que requer autenticação. Um desafio de autenticação é emitido, por exemplo, quando um usuário anônimo solicita um recurso restrito ou segue um link de logon. A autorização invoca um desafio usando os esquemas de autenticação especificados ou o padrão se nenhum for especificado. Consulte ChallengeAsync. Exemplos de desafio de autenticação incluem:

  • Um esquema de autenticação cookie que redireciona o usuário para uma página de logon.
  • Um esquema de portador JWT que retorna um resultado 401 com um cabeçalho www-authenticate: bearer.

Uma ação de desafio deve informar ao usuário qual mecanismo de autenticação usar para acessar o recurso solicitado.

Proibir

A ação de proibição de um esquema de autenticação é chamada pela Autorização quando um usuário autenticado tenta acessar um recurso que não tem permissão para acessar. Consulte ForbidAsync. Exemplos de proibição de autenticação incluem:

  • Um esquema de autenticação cookie que redireciona o usuário para uma página que indica que o acesso foi proibido.
  • Um esquema de portador JWT que retorna um resultado 403.
  • Um esquema de autenticação personalizado que redireciona para uma página em que o usuário pode solicitar acesso ao recurso.

Uma ação de proibição pode informar ao usuário:

  • Que ele está autenticado.
  • Que ele não tem permissão para acessar o recurso solicitado.

Consulte os seguintes links para conhecer as diferenças entre desafio e proibição:

Provedores de autenticação por locatário

O ASP.NET Core não tem uma solução interna para autenticação multilocatário. Embora seja possível que os clientes escrevam uma usando os recursos internos, recomendamos que considerem Orchard Core, ABP Framework ou Finbuckle.MultiTenant para autenticação multilocatário.

O Orchard Core é:

  • Uma estrutura de aplicativos de software livre, modular e multilocatário criada com o ASP.NET Core.
  • Um CMS (sistema de gerenciamento de conteúdo) criado com base nessa estrutura de aplicativo.

Consulte a fonte Orchard Core para obter um exemplo de provedores de autenticação por locatário.

O ABP Framework dá suporte a vários padrões de arquitetura, incluindo modularidade, microsserviços, design controlado por domínio e multilocatário. Consulte Origem do ABP Framework no GitHub.

Finbuckle.MultiTenant:

  • Software livre
  • Fornece resolução de locatário
  • Leve
  • Fornece isolamento de dados
  • Configurar o comportamento do aplicativo de forma única para cada locatário

Recursos adicionais

Por Mike Rousos

Autenticação é o processo de determinar a identity de um usuário. Autorização é o processo de determinar se um usuário tem acesso a um recurso. No ASP.NET Core, a autenticação é tratada pelo serviço de autenticação, IAuthenticationService, que é usado pelo middleware de autenticação. O serviço de autenticação usa manipuladores de autenticação registrados para realizar ações relacionadas à autenticação. Exemplos de ações relacionadas à autenticação incluem:

  • Autenticar um usuário.
  • Responder quando um usuário não autenticado tenta acessar um recurso restrito.

Os manipuladores de autenticação registrados e suas opções de configuração são chamados de "esquemas".

Os esquemas de autenticação são especificados registrando serviços de autenticação em Program.cs:

Por exemplo, o seguinte código registra serviços de autenticação e manipuladores para cookie e esquemas de autenticação de portador JWT:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme,
        options => builder.Configuration.Bind("JwtSettings", options))
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
        options => builder.Configuration.Bind("CookieSettings", options));

O parâmetro AddAuthentication JwtBearerDefaults.AuthenticationScheme é o nome do esquema a ser usado por padrão quando um esquema específico não é solicitado.

Se vários esquemas forem usados, políticas de autorização (ou atributos de autorização) poderão especificar o esquema de autenticação (ou esquemas) de que dependem para autenticar o usuário. No exemplo acima, o esquema de autenticação cookie pode ser usado especificando seu nome (CookieAuthenticationDefaults.AuthenticationScheme por padrão, embora um nome diferente possa ser fornecido ao chamar AddCookie).

Em alguns casos, a chamada para AddAuthentication é feita automaticamente por outros métodos de extensão. Por exemplo, ao usar o ASP.NET CoreIdentity, AddAuthentication é chamado internamente.

O middleware de Autenticação é adicionado em Program.cs chamando UseAuthentication. Chamar UseAuthentication registra o middleware que usa os esquemas de autenticação registrado anteriormente. Chame UseAuthentication antes de qualquer middleware que dependa de usuários serem autenticados.

Conceitos de autenticação

A autenticação é responsável por fornecer o ClaimsPrincipal autorização para tomar decisões de permissão. Há várias abordagens de esquema de autenticação para selecionar qual manipulador de autenticação é responsável por gerar o conjunto correto de declarações:

Não há investigação automática de esquemas. Se o esquema padrão não for especificado, o esquema deverá ser especificado no atributo de autorização, caso contrário, o seguinte erro será gerado:

InvalidOperationException: nenhum authenticationScheme foi especificado e não foi encontrado nenhum DefaultAuthenticateScheme. Os esquemas padrão podem ser definidos usando AddAuthentication(string defaultScheme) ou AddAuthentication(Action<AuthenticationOptions> configureOptions).

Esquema de autenticação

O esquema de autenticação pode selecionar qual manipulador de autenticação é responsável por gerar o conjunto correto de declarações. Para obter mais informações, consulte Autorizar com um esquema específico.

Um esquema de autenticação é um nome que corresponde a:

  • Um manipulador de autenticação.
  • Opções para configurar essa instância específica do manipulador.

Os esquemas são úteis como um mecanismo para fazer referência à autenticação, ao desafio e à proibição de comportamentos do manipulador associado. Por exemplo, uma política de autorização pode usar nomes de esquema para especificar qual esquema de autenticação (ou esquemas) deve ser usado para autenticar o usuário. Ao configurar a autenticação, é comum especificar o esquema de autenticação padrão. O esquema padrão é usado, a menos que um recurso solicite um esquema específico. Também é possível:

  • Especificar diferentes esquemas padrão a serem usados para autenticar, desafiar e proibir ações.
  • Combinar vários esquemas em um usando esquemas de política.

Manipulador de autenticação

Um manipulador de autenticação:

Com base na configuração do esquema de autenticação e no contexto da solicitação de entrada, os manipuladores de autenticação:

  • Construa objetos AuthenticationTicket que representem a identity do usuário se a autenticação for bem-sucedida.
  • Retornará "nenhum resultado" ou "falha" se a autenticação não for bem-sucedida.
  • Tenha métodos para desafiar e proibir ações para quando os usuários tentarem acessar recursos:
    • Que eles não estão autorizados a acessar (proibir).
    • Quando eles não estão autenticados (desafio).

RemoteAuthenticationHandler<TOptions> versus AuthenticationHandler<TOptions>

RemoteAuthenticationHandler<TOptions> é a classe para autenticação que requer uma etapa de autenticação remota. Quando a etapa de autenticação remota for concluída, o manipulador retornará ao CallbackPath definido pelo manipulador. O manipulador conclui a etapa de autenticação usando as informações passadas para o caminho do retorno de chamada HandleRemoteAuthenticateAsync. OAuth 2.0 e OIDC usam esse padrão. JWT e cookies não, pois podem usar diretamente o cabeçalho do portador e cookie para autenticar. O provedor hospedado remotamente neste caso:

  • É o provedor de autenticação.
  • Exemplos incluem o Facebook, o Twitter, o Google, o Microsoft e qualquer outro provedor de OIDC que manipula a autenticação de usuários usando o mecanismo de manipuladores.

Authenticate

A ação de autenticação de um esquema de autenticação é responsável por construir a identity do usuário com base no contexto de solicitação. Ela retorna um AuthenticateResult que indica se a autenticação foi bem-sucedida e, nesse caso, a identity do usuário em um tíquete de autenticação. Consulte AuthenticateAsync. Exemplos de autenticação incluem:

  • Um esquema de autenticação cookie que constrói a identity do usuário com base em cookies.
  • Um esquema de portador JWT que desserializa e valida um token de portador JWT para construir a identity do usuário.

Desafio

Um desafio de autenticação é invocado pela Autorização quando um usuário não autenticado solicita um ponto de extremidade que requer autenticação. Um desafio de autenticação é emitido, por exemplo, quando um usuário anônimo solicita um recurso restrito ou segue um link de logon. A autorização invoca um desafio usando os esquemas de autenticação especificados ou o padrão se nenhum for especificado. Consulte ChallengeAsync. Exemplos de desafio de autenticação incluem:

  • Um esquema de autenticação cookie que redireciona o usuário para uma página de logon.
  • Um esquema de portador JWT que retorna um resultado 401 com um cabeçalho www-authenticate: bearer.

Uma ação de desafio deve informar ao usuário qual mecanismo de autenticação usar para acessar o recurso solicitado.

Proibir

A ação de proibição de um esquema de autenticação é chamada pela Autorização quando um usuário autenticado tenta acessar um recurso que não tem permissão para acessar. Consulte ForbidAsync. Exemplos de proibição de autenticação incluem:

  • Um esquema de autenticação cookie que redireciona o usuário para uma página que indica que o acesso foi proibido.
  • Um esquema de portador JWT que retorna um resultado 403.
  • Um esquema de autenticação personalizado que redireciona para uma página em que o usuário pode solicitar acesso ao recurso.

Uma ação de proibição pode informar ao usuário:

  • Que ele está autenticado.
  • Que ele não tem permissão para acessar o recurso solicitado.

Consulte os seguintes links para conhecer as diferenças entre desafio e proibição:

Provedores de autenticação por locatário

O ASP.NET Core não tem uma solução interna para autenticação multilocatário. Embora seja possível que os clientes escrevam uma usando os recursos internos, recomendamos que considerem o Orchard Core ou o ABP Framework para autenticação multilocatário.

O Orchard Core é:

  • Uma estrutura de aplicativos de software livre, modular e multilocatário criada com o ASP.NET Core.
  • Um CMS (sistema de gerenciamento de conteúdo) criado com base nessa estrutura de aplicativo.

Consulte a fonte Orchard Core para obter um exemplo de provedores de autenticação por locatário.

O ABP Framework dá suporte a vários padrões de arquitetura, incluindo modularidade, microsserviços, design controlado por domínio e multilocatário. Consulte Origem do ABP Framework no GitHub.

Recursos adicionais

Por Mike Rousos

Autenticação é o processo de determinar a identity de um usuário. Autorização é o processo de determinar se um usuário tem acesso a um recurso. No ASP.NET Core, a autenticação é tratada pelo serviço de autenticação, IAuthenticationService, que é usado pelo middleware de autenticação. O serviço de autenticação usa manipuladores de autenticação registrados para realizar ações relacionadas à autenticação. Exemplos de ações relacionadas à autenticação incluem:

  • Autenticar um usuário.
  • Responder quando um usuário não autenticado tenta acessar um recurso restrito.

Os manipuladores de autenticação registrados e suas opções de configuração são chamados de "esquemas".

Os esquemas de autenticação são especificados registrando serviços de autenticação em Startup.ConfigureServices:

Por exemplo, o seguinte código registra serviços de autenticação e manipuladores para cookie e esquemas de autenticação de portador JWT:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme,
        options => Configuration.Bind("JwtSettings", options))
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
        options => Configuration.Bind("CookieSettings", options));

O parâmetro AddAuthentication JwtBearerDefaults.AuthenticationScheme é o nome do esquema a ser usado por padrão quando um esquema específico não é solicitado.

Se vários esquemas forem usados, políticas de autorização (ou atributos de autorização) poderão especificar o esquema de autenticação (ou esquemas) de que dependem para autenticar o usuário. No exemplo acima, o esquema de autenticação cookie pode ser usado especificando seu nome (CookieAuthenticationDefaults.AuthenticationScheme por padrão, embora um nome diferente possa ser fornecido ao chamar AddCookie).

Em alguns casos, a chamada para AddAuthentication é feita automaticamente por outros métodos de extensão. Por exemplo, ao usar o ASP.NET CoreIdentity, AddAuthentication é chamado internamente.

O middleware de Autenticação é adicionado em Startup.Configure chamando UseAuthentication. Chamar UseAuthentication registra o middleware que usa os esquemas de autenticação registrado anteriormente. Chame UseAuthentication antes de qualquer middleware que dependa de usuários serem autenticados. Ao usar o roteamento de ponto de extremidade, a chamada para UseAuthentication deve ser executada:

  • Depois de UseRouting, para que as informações de rota fiquem disponíveis para decisões de autenticação.
  • Antes de UseEndpoints, para que os usuários sejam autenticados antes de acessar os pontos de extremidade.

Conceitos de autenticação

A autenticação é responsável por fornecer o ClaimsPrincipal autorização para tomar decisões de permissão. Há várias abordagens de esquema de autenticação para selecionar qual manipulador de autenticação é responsável por gerar o conjunto correto de declarações:

Não há investigação automática de esquemas. Se o esquema padrão não for especificado, o esquema deverá ser especificado no atributo de autorização, caso contrário, o seguinte erro será gerado:

InvalidOperationException: nenhum authenticationScheme foi especificado e não foi encontrado nenhum DefaultAuthenticateScheme. Os esquemas padrão podem ser definidos usando AddAuthentication(string defaultScheme) ou AddAuthentication(Action<AuthenticationOptions> configureOptions).

Esquema de autenticação

O esquema de autenticação pode selecionar qual manipulador de autenticação é responsável por gerar o conjunto correto de declarações. Para obter mais informações, consulte Autorizar com um esquema específico.

Um esquema de autenticação é um nome que corresponde a:

  • Um manipulador de autenticação.
  • Opções para configurar essa instância específica do manipulador.

Os esquemas são úteis como um mecanismo para fazer referência à autenticação, ao desafio e à proibição de comportamentos do manipulador associado. Por exemplo, uma política de autorização pode usar nomes de esquema para especificar qual esquema de autenticação (ou esquemas) deve ser usado para autenticar o usuário. Ao configurar a autenticação, é comum especificar o esquema de autenticação padrão. O esquema padrão é usado, a menos que um recurso solicite um esquema específico. Também é possível:

  • Especificar diferentes esquemas padrão a serem usados para autenticar, desafiar e proibir ações.
  • Combinar vários esquemas em um usando esquemas de política.

Manipulador de autenticação

Um manipulador de autenticação:

Com base na configuração do esquema de autenticação e no contexto da solicitação de entrada, os manipuladores de autenticação:

  • Construa objetos AuthenticationTicket que representem a identity do usuário se a autenticação for bem-sucedida.
  • Retornará "nenhum resultado" ou "falha" se a autenticação não for bem-sucedida.
  • Tenha métodos para desafiar e proibir ações para quando os usuários tentarem acessar recursos:
    • Que eles não estão autorizados a acessar (proibir).
    • Quando eles não estão autenticados (desafio).

RemoteAuthenticationHandler<TOptions> versus AuthenticationHandler<TOptions>

RemoteAuthenticationHandler<TOptions> é a classe para autenticação que requer uma etapa de autenticação remota. Quando a etapa de autenticação remota for concluída, o manipulador retornará ao CallbackPath definido pelo manipulador. O manipulador conclui a etapa de autenticação usando as informações passadas para o caminho do retorno de chamada HandleRemoteAuthenticateAsync. OAuth 2.0 e OIDC usam esse padrão. JWT e cookies não, pois podem usar diretamente o cabeçalho do portador e cookie para autenticar. O provedor hospedado remotamente neste caso:

  • É o provedor de autenticação.
  • Exemplos incluem o Facebook, o Twitter, o Google, o Microsoft e qualquer outro provedor de OIDC que manipula a autenticação de usuários usando o mecanismo de manipuladores.

Authenticate

A ação de autenticação de um esquema de autenticação é responsável por construir a identity do usuário com base no contexto de solicitação. Ela retorna um AuthenticateResult que indica se a autenticação foi bem-sucedida e, nesse caso, a identity do usuário em um tíquete de autenticação. Consulte AuthenticateAsync. Exemplos de autenticação incluem:

  • Um esquema de autenticação cookie que constrói a identity do usuário com base em cookies.
  • Um esquema de portador JWT que desserializa e valida um token de portador JWT para construir a identity do usuário.

Desafio

Um desafio de autenticação é invocado pela Autorização quando um usuário não autenticado solicita um ponto de extremidade que requer autenticação. Um desafio de autenticação é emitido, por exemplo, quando um usuário anônimo solicita um recurso restrito ou segue um link de logon. A autorização invoca um desafio usando os esquemas de autenticação especificados ou o padrão se nenhum for especificado. Consulte ChallengeAsync. Exemplos de desafio de autenticação incluem:

  • Um esquema de autenticação cookie que redireciona o usuário para uma página de logon.
  • Um esquema de portador JWT que retorna um resultado 401 com um cabeçalho www-authenticate: bearer.

Uma ação de desafio deve informar ao usuário qual mecanismo de autenticação usar para acessar o recurso solicitado.

Proibir

A ação de proibição de um esquema de autenticação é chamada pela Autorização quando um usuário autenticado tenta acessar um recurso que não tem permissão para acessar. Consulte ForbidAsync. Exemplos de proibição de autenticação incluem:

  • Um esquema de autenticação cookie que redireciona o usuário para uma página que indica que o acesso foi proibido.
  • Um esquema de portador JWT que retorna um resultado 403.
  • Um esquema de autenticação personalizado que redireciona para uma página em que o usuário pode solicitar acesso ao recurso.

Uma ação de proibição pode informar ao usuário:

  • Que ele está autenticado.
  • Que ele não tem permissão para acessar o recurso solicitado.

Consulte os seguintes links para conhecer as diferenças entre desafio e proibição:

Provedores de autenticação por locatário

A estrutura do ASP.NET Core não tem uma solução interna para autenticação multilocatário. Embora seja possível que os clientes escrevam um aplicativo com autenticação multilocatário, recomendamos usar uma das seguintes estruturas de aplicativos do ASP.NET Core que dão suporte à autenticação multilocatário:

Orchard Core

Orchard Core. Consulte a fonte Orchard Core para obter um exemplo de provedores de autenticação por locatário.

ABP Framework

O ABP Framework dá suporte a vários padrões de arquitetura, incluindo modularidade, microsserviços, design controlado por domínio e multilocatário. Consulte Origem do ABP Framework no GitHub.

Recursos adicionais