ASP .NET Core - Habilitando e usando CORS

 Neste artigo eu vou mostrar como habilitar e utilizar o recurso CORS em aplicações ASP .NET Core.

Por padrão, os navegadores seguem a política de mesma origem, ou 'same-origem policy', assim, a segurança do navegador não permite que páginas da Web façam requisições AJAX para outro domínio. Essa prevenção é chamada de 'same-origin policy' ou 'política de mesma origem'. Isso impede que outro site leia dados confidenciais de outro site.

Nota: Duas páginas têm a mesma origem se o protocolo, a porta (se for especificada uma) e o host forem os mesmos para ambas as páginas.

Atualmente com a interoperabilidade entre APIs e sistemas na web essa restrição não se justifica em muitos cenários, sendo necessário uma maneira de permitir as requisições entre domínios distintos. Assim, o CORS é uma maneira de contornar essa limitação de segurança por motivos legítimos.

O mais comum no contexto da ASP.NET Core é que você está construindo uma Single Page Application e deseja hospedar sua API em outro domínio.

O
Cross-Origin Resource Sharing ou 'compartilhamento de recursos de origem cruzada' cujo acrônimo é CORS é um padrão W3C sendo uma especificação de uma tecnologia de navegadores que define meios para um servidor permitir que seus recursos sejam acessados por uma página web de um domínio diferente.



Usando o CORS, um servidor pode permitir algumas solicitações de origem cruzada (domínio) e rejeitar outras. O
CORS é mais flexível e seguro do que as técnicas anteriores, como o JSONP.

JSONP ou "JSON with padding" é um complemento ao formato de dados JSON. Ele provê um método para enviar requisições de dados de um servidor para um domínio diferente, uma coisa proibida pelos navegadores típicos por causa da Política de mesma origem.

Então podemos usar o CORS para permitir requisições de origem cruzada e podemos fazer isso usando dois métodos :

  1. Usando o Middleware - Habilite o CORS e adicione os serviços CORS e defina a política usando o middleware para passar o nome da política;
  2. Usando o MVC  - Adicione o serviço CORS e habilite o CORS para as Action, o Controller ou globalmente;

A seguir veremos como usar cada uma dessas opções.

Configurando o CORS na ASP .NET Core

A partir da ASP .NET Core 2.0, que introduziu o meta package Microsoft.AspNetCore.All, não é preciso mais instalar o pacote Microsoft.AspNetCore.Cors.

Se você duvida basta abrir o pacote Nuget e expandir o Microsoft.AspNetCore.All e verificar que o Microsoft.AspNetCore.Cors já esta presente:

Então ficou mais fácil.

A seguir você precisa adicionar o serviço CORS no método ConfigureServices da classe Startup :

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AspNetCore_CORS
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
                 services.AddMvc();
            services.AddCors();
        }
        .....
}

A seguir você precisa adicionar o middleware CORS na sua aplicação no método Configure da classe Startup:

Para ativar o CORS no middleware, precisamos adicionar o pipeline de solicitação, usando o método de extensão UseCors no método Configure da classe Startup. É semelhante ao MVC e podemos especificar uma política de origem cruzada ao adicionar o middleware CORS, usando a classe CorsPolicyBuilder.

O método UseCors possui duas versões de sobrecarga, em que a primeira aceita apenas o nome poli como um argumento.

Portanto, com esse método, precisamos passar o nome da política CORS como uma string.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();
            app.UseCors(option => option.AllowAnyOrigin());;
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

O segundo método aceita uma Task do tipo CorsPolicyBuilder. Usando a expressão lamba, podemos passar o objeto CorsPolicyBuilder.

Habilitando o CORS no MVC

Podemos aplicar CORS no MVC por Action, por Controller ou globalmente. O serviço CORS MVC é diferente do serviço do middleware CORS.

1 -  Aplicando CORS por Action

Para especificar CORS por Action, inclua o atributo EnableCors no topo da Action. Este atributo aceita o nome da politica como um argumento.

Você deverá usar o namespace using Microsoft.AspNetCore.Cors;

Exemplo:

using AspNetCore_CORS.Models;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace AspNetCore_CORS.Controllers
{
    public class HomeController : Controller
    {
        [EnableCors("AllowSpecificOrigin")]
        public IActionResult Index()
        {
            return View();
        }
      ....
}

2 -  Aplicando CORS por Controller

Para especificar CORS por Action, inclua o atributo EnableCors no topo do Controller.Isso irá aplicar o CORS a cada método Action do controlador.

Exemplo:

using AspNetCore_CORS.Models;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace AspNetCore_CORS.Controllers
{
     [EnableCors("AllowSpecificOrigin")]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
      ....
}

3- Aplicando o CORS em toda a aplicação

Podemos habilitar o CORS em toda a aplicação ou seja globalmente. 

Isso irá aplicar o CORS a todos os controladores incluindo o filtro CorsAuthorizationFilterFactory na coleção de filtros globais no método ConfigureServices da classe Startup.

Exemplo:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Cors.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AspNetCore_CORS
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.Configure<MvcOptions>(options => {
                options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
            });
        }
        ....
}       

4- Desabilitando o CORS

Podemos usar o atributo DisableCors para desabilitar o CORS para um controlador ou uma Action.

Exemplo:

using AspNetCore_CORS.Models;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace AspNetCore_CORS.Controllers
{
    public class HomeController : Controller
    {
         [DisableCors]
        public IActionResult Index()
        {
            return View();
        }
      ....
}

Exemplos de políticas CORS que podemos definir usando UserCors

A seguir temos alguns exemplos de políticas CORS definidas usando UserCors:

1- Configurando as origens permitidas

Usando o método WithOrigins da classe CorsPolicyBuilder podemos definir uma ou mais origens específicas:

Abaixo temos um exemplo que permite todas as origens:

2- Definindo os métodos HTTP permitidos

Usando o método WithMethods podemos definir um ou mais métodos HTTP específicos:
No código abaixo podemos permitir todos os métodos:

3- Definindo os headers das requisições permitidas

Usando o método WithHeaders podemos definir um ou mais headers específicos

Permitindo todos os headers :

4- Credenciais em requisições Cross-Origin

O  navegador não envia as credenciais com uma requisição de origem cruzada. Em alguns casos precisamos passar as credenciais em uma requisição CORS. O cliente deverá definir XMLHttpRequest.withCredentials  para true para enviar as credenciais com a requisição.

O código abaixo habilita o envio das credenciais em requisições cross-origin:

5- Define o tempo de expiração preflight

O header 'Access-Control-Max-Age' especifica quanto tempo o response para a requisição preflight pode permanecer no cache.

O código a seguir é usado para definir um tempo de expiração para esta requisição.

Nota:  Uma requisição preflight CORS é uma requisição CORS que verifica se o protocolo CORS é entendido.

Definindo políticas CORS nomeadas e usando a política pelo nome em tempo de execução

Podemos definir um conjunto de políticas CORS em um grupo e a seguir podemos selecionar uma política para ser executa em tempo de execução.

Para fazer isso precisamos adicionar o grupo de políticas no método ConfigureServices usando o método AddCors, e, depois selecionar a política desejada no método Configure da classe Startup.

Exemplo:

1- Método ConfigureServices - definindo o conjunto de políticas CORS
       public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddCors(option => {
                option.AddPolicy("AllowSpecificOrigin", policy => policy.WithOrigins("http://macoratti.net"));
                option.AddPolicy("AllowGetMethod", policy => policy.WithMethods("GET"));
            });
        }

2- Método Configure - escolhendo uma política
 
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseCors("AllowSpecificOrigin");
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

Exemplo de configuração de CORS no .NET 6  feito na classe Program:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
   options.AddDefaultPolicy(
     policy =>
     {
       policy.AllowAnyOrigin()
           .AllowAnyHeader()
           .AllowAnyMethod();
     });
});
...

app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

E assim, apresentei os conceitos básicos sobre CORS e como configurar e usar o recurso em aplicações ASP .NET Core.

Até o próximo artigo...

"Deus nunca foi visto por alguém. O Filho unigênito (Jesus), que está no seio do Pai, esse o revelou."
João 1:18

Referências:


José Carlos Macoratti