APIs e Microsserviços

22 mai, 2018

ASP .NET Web API – Implementando a segurança via Tokens – Parte 03

Publicidade

Continuando o artigo anterior, vamos agora implementar a segurança em uma Web API usando Tokens. Para isso, teremos que realizar as seguintes tarefas:

  • Transformar a nossa Web API em uma aplicação OWINAtivar o CORS na Web API via OWIN
  • Ativar a geração de Tokens via OAuth
  • Testar os serviços usando o Postman

Transformando a Web API em uma aplicação OWIN

O objetivo da especificação OWIN é que a nossa aplicação não fique vinculada a um Sistema Operacional, nem a um servidor. Além disso, aplicações OWIN tem um melhor desempenho. Com isso em mente, podemos transformar nossa Web API em uma aplicação OWIN aplicando alguns pacotes.

Após criar sua aplicação Web API usando o template Empty, acesse o menu Tools > Nugetr Package Manager > Package Manager Console para abrir o console do Nuget, e a seguir instale os pacotes abaixo:

  • Install-Package Microsoft.AspNet.WebApi.Owin: instala o protocolo OWIN
  • Install-Package Microsoft.Owin.Host.SystemWeb: a implementação Microsoft do OWIN (Katana)

Ativando o CORS na Web API via OWIN

Como temos o nosso backend, representando pela Web API – sendo esta separada do cliente ou Front-end -, com certeza precisaremos receber requisições de domínios distintos, e para isso teremos que habilitar o CORS em nossa aplicação Web API, pois sem fazer isso, qualquer requisição feita por um domínio diferente vai gerar a mensagem de erro: ‘access-control-allow-origen’.

A especificação CORS (Cross-Origin Resource Sharing ou Compartilhamento de recursos de origem cruzada é uma especificação sobre como trocar recursos entre o cliente e o backend quando o cliente, geralmente um navegador, tenta acessar um domínio distinto.

É um conjunto de regras, uma especificação da W3C para que tipo de recursos podem ser acessados, e como os limitar. Essas regras são implementadas pelos navegadores, e é este (o browser) que limita o acesso. Essas regras impuseram-se por razões de segurança, para evitar que scripts na página possam acessar livremente e fazer pedidos a outros sites e interagir com eles.

Ao ativar o CORS, estamos permitindo o acesso de outro site mesmo estando em domínios diferentes. Para ativá-lo em nossa Web API temos que instalar o pacote abaixo no projeto:

  • Install-Package Microsoft.Owin.Cors

Implementando o código na classe Startup

Agora que temos os pacotes instalados no projeto, criaremos uma classe Startup onde vamos configurar os recursos descritos acima.

No menu Project, clique em bAdd New Item” e selecione o template “OWIN Startup Class“, informando o nome “Startup.cs” e clique no botão “Add“;

Vamos iniciar definindo algumas configuracões básicas:

  • Configurar a Web API
  • Configurar a rota
  • Ativar o CORS
  • Ativar a configuração da Web API
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Web.Http;
[assembly: OwinStartup(typeof(FuncionariosAPIService.Startup))]
namespace FuncionariosAPIService
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // configuracao WebApi
            var config = new HttpConfiguration(); 
           // configurando rotas
           config.MapHttpAttributeRoutes();
           config.Routes.MapHttpRoute(
                 name: "DefaultApi",
                 routeTemplate: "api/{controller}/{id}",
                 defaults: new { id = RouteParameter.Optional }
            );
            // ativando cors
            app.UseCors(CorsOptions.AllowAll);
           // ativando configuração WebApi
            app.UseWebApi(config);
        }     
    }
}

Com essas configurações, temos agora a nossa Web API como uma aplicação OWIN com o CORS ativado. Precisamos avançar e agora definir a implementação do token que vai permitir acessar nossa Web API. Para poder fazer isso, vamos ter que instalar o pacote abaixo em nosso projeto:

  • install-package Microsoft.Owin.Security.OAuth

Agora podemos implementar o método AtivarGeracaoTokenAcesso() para ativar o acesso via Token e após fazer a autenticação do usuário, vamos gerar o token para esse usuário.

[assembly: OwinStartup(typeof(FuncionariosAPIService.Startup))]
namespace FuncionariosAPIService
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // configuracao WebApi
            var config = new HttpConfiguration(); 
           // configurando rotas
           config.MapHttpAttributeRoutes();
           config.Routes.MapHttpRoute(
                 name: "DefaultApi",
                 routeTemplate: "api/{controller}/{id}",
                 defaults: new { id = RouteParameter.Optional }
            );
            // ativando cors
            app.UseCors(CorsOptions.AllowAll);
            // ativando a geração do token
            AtivarGeracaoTokenAcesso(app)
           // ativando configuração WebApi
            app.UseWebApi(config);
        }     
    }
}

A seguir temos o código do método AtivarGeracaoTokenAcesso(app):

  private void AtivarGeracaoTokenAcesso(IAppBuilder app)
        {
            var opcoesConfiguracaoToken = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),
                Provider = new ProviderDeTokensDeAcesso()
            };
            app.UseOAuthAuthorizationServer(opcoesConfiguracaoToken);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }

Vamos entender o código acima:

A) Criamos uma variável do tipo OAuthAuthorizationServerOptions, que fornece informações necessárias para controlar o comportamento do middleware do Authorization Server.

B) A seguir, definimos as propriedades:

  • AllowInsecureHttp: Igual a true, permitindo assim o acesso ao endereço que gera o token de acesso sem a necessidade de usar HTTPS;
  • TokenEndPointPaht: Define o endereço que fornece o token de acesso. Deve iniciar com uma barra /token;
  • AccessTokenExpireTimeSpan: O período de tempo em que o token de acesso permanece válido após ser emitido – o padrão é vinte minutos. Espera-se que o aplicativo cliente atualize ou adquira um novo token de acesso após o término do token. Estamos definindo o tempo de 1 hora
  • Provider: É o objeto fornecido pelo aplicativo para processar eventos gerados pelo middleware do Authorization Server. O aplicativo pode implementar a interface completamente ou criar uma instância de OAuthAuthorizationServerProvider e atribuir delegados apenas aos eventos que deseja processar. Precisamos criar a classe ProviderDeTokenDeAcesso().

Para concluir, vamos ativar o uso de tokens no projeto:

C) Adiciona os recursos da autorização do servidor OAuth2 à nossa aplicação OWIN. Este middleware realiza o processamento da solicitação para os nós de extremidade de autorização e token definidos pela especificação OAuth2.

  • app.UseOAuthAuthorizationServer(opcoesConfiguracaoToken);

D) Gera uma autenticação do portador do OAuth para o aplicativo OWIN. A classe de opções fornece informações necessárias para controlar o comportamento do middleware Bearer Authentication.

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

Com isso, temos ativada a geração de tokens de acesso na nossa Web API. Só falta definir o Provider e verificar a autenticação do usuário usando a nossa classe FuncionariosSeguranca.

Vamos criar a classe ProviderDeTokensDeAcesso() que herda da classe OAuthAuthorizationServerProvider com o código abaixo:

using FuncionariosAPIService.Services;
using Microsoft.Owin.Security.OAuth;
using System.Security.Claims;
using System.Threading.Tasks;
namespace FuncionariosAPIService
{
    public class ProviderDeTokensDeAcesso : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            if (FuncionariosSeguranca.Login(context.UserName, context.Password))
            {
                var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                identity.AddClaim(new Claim("sub", context.UserName));
                identity.AddClaim(new Claim("role", "user"));
                context.Validated(identity);
            }
            else
            {
                context.SetError("acesso inválido", "As credenciais do usuário não conferem....");
                return;
            }
        }
    }
}

O código dessa classe verifica se as credenciais do usuário são válidas, e neste caso gera um token de acesso. Para isso, estamos usando a classe FuncionariosSeguranca(). Essa classe implementa os seguintes métodos:

  • O método ValidateClientAuthentication realiza as validações quando o usuário se autenticar usando o token de acesso gerado;
  • O método GrantResourceOwnerCredentials que recebe um context com as informações passadas pelo usuário. Daí obtemos o nome do usuário – Username e a senha – Password;

No nosso exemplo, se as credenciais do usuário forem inválidas, será retornado uma mensagem de erro:

context.SetError(“acesso inválido”, “As credenciais do usuário não conferem….”);

Pronto! Já temos tudo pronto e agora podemos testar a nossa implementação. Na próxima parte do artigo vamos fazer isso usando o Postman.