Olá pessoal! Tudo bem? Depois de um pequeno debate sobre as vantagens teóricas de usarmos novas formas de autenticação com WebApis, vamos colocar a mão na massa. Neste artigo, vamos elencar as vantagens práticas de usar tokens de acesso e implementar uma WebApi que precisa de tokens de acesso para acessar recursos.
Todo o código fonte usado neste artigo está disponível no GitHub, fique a vontade para baixá-lo e estudá-lo.
Dentro os vários benefícios, eu destaco:
- Baixíssimo acoplamento: Toda a lógica de autenticação estará na WebApi. Qualquer sistema que acesse seu back-end só precisa saber onde obter os tokens de acesso e como repassá-los para autorizar o usuário.
-
Baixo trânsito de informações: Todas as informações referentes ao usuário ficam no token. Se um usuário tem alguma classificação interna, ela está guardada no token de acesso. As informações ficam criptografadas e apenas a WebApi entende que informações adicionais são estas.
-
Não depende de cookies: WebApis com tokens são perfeitas para apps mobile, que podem guardar os tokens de acesso de ouras formas. Logicamente, sites que acessam estas WebApis podem usar cookies para guardar o token.
-
Prazo de validade bem definido: Se você configura o token para durar 60 minutos, ele totalmente a validade depois de 60 minutos. Não é possível usar um token vencido, que se torna completamente inútil.
-
Independe de como as informações serão validadas: Não importa se você tem um banco de dados, precisa acessar outra API para saber se o usuário é válido ou usa contas de usuário do Windows. A emissão de tokens de acesso independe da tecnologia de validação dos dados.
Atenção: A WebApi não pode ter nenhuma forma de autenticação atrelada a ela – é a tecnologia de tokens de acesso que fará este trabalho.
Adicionar o recurso de tokens de acesso numa WebApi não é exatamente complexo, mas você precisa primeiramente fazer dois procedimentos, já descritos aqui no blog:
Ambos os passos são necessários porque as bibliotecas de tokens de acesso rodam em aplicações OWIN e os endereços da WebApi agora serão acessados por outros serviços, em outros servidores – por isso a aplicação OWIN precisa ter suporte ao Cors.
Depois de seguir ambos os artigos, seu projeto WebApi deve ter estes três pacotes instalados:
Install-Package Microsoft.AspNet.WebApi.Owin Install-Package Microsoft.Owin.Host.SystemWeb Install-Package Microsoft.Owin.Cors
Vamos dar uma olhada na classe Startup depois de seguir os procedimentos de ambos os artigos.
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); } }
Como você pode ver, temos uma Owin Application devidamente configurada e com o Cors configurado para as páginas. Vamos então ativar o acesso usando tokens. Clique com o botão direito do mouse no projeto e escolha Manage NuGet Packages….

O pacote que precisamos instalar é o Microsoft.Owin.Security.OAuth.

Após a instalação, voltemos à classe Startup. Imediatamente antes de ativar de fato a OWIN Application com a configuração de WebApi, adicionemos a função AtivandoAccessToken, que recebe como padrão a variável app.

Obviamente precisamos criar o método – neste caso, logo abaixo de Configuration.

Neste método, vamos configurar e ativar o uso de tokens de acesso. Em primeiro lugar, vamos criar uma variável do tipo OAuthAuthorizationServerOptions, que, como o nome indica, agrupa as opções de configuração do fornecimento de tokens de acesso.
Mais ou menos assim:
var opcoesConfiguracaoToken = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromHours(1) };
O que estamos configurando com isso:
- Permitindo acesso ao endereço de fornecimento do token de acesso sem precisar de HTTPS (AllowInsecureHttp). Obviamente, num ambiente de produção, o valor deve ser false.
-
Configurando o endereço do fornecimento do token de acesso (TokenEndpointPath).
-
Configurando por quanto tempo um token de acesso já forncedido valerá (AccessTokenExpireTimeSpan).
Neste caso, o token fornecido valerá por duas horas e o endereço é servidor/token – esta é a parte que configuramos.
Vamos agora ativar o uso de tokens no projeto. Logo abaixo, vamos colocar este código:
app.UseOAuthAuthorizationServer(opcoesConfiguracaoToken); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
Estas duas linhas ativam o fornecimento de tokens de acesso numa WebApi. Mas percebeu que estamos esquecendo o principal? Como verificar usuário e senha para fornecer tokens de acesso? Precisamos configurar o Provider dos tokens. De volta à configuração, vamos adicionar o Provider:
var opcoesConfiguracaoToken = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromHours(2), Provider = new ProviderDeTokensDeAcesso() };
Note que uma instância da classe ProviderDeTokensDeAcesso é o nosso Provider. Com isso, terminamos de configurar o uso de tokens de acesso dentro de Startup.

Agora precisamos criar a classe ProviderDeTokensDeAcesso, lembra? É ela que verifica se as informações do usuário e senha são válidas para fornecer um token de acesso. Crie a classe normalmente – ela deve herdar de OAuthAuthorizationServerProvider
public class ProviderDeTokensDeAcesso : OAuthAuthorizationServerProvider { }
Dentro da classe ProviderDeTokesDeAcesso, precisamos primeiramente implementar o método ValidateClientAuthetication, que é responsável por fazer validações extras quando o usuário se autentica com o token de acesso.
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); }
O outro método que deve ser implementado – GrantResourceOwnerCredentials – é o responsável por fornecer o token de acesso com base no usuário e senha.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { }
E vale a pena parar aqui para uma observação. Como o foco deste artigo é o funcionamento dos tokens de acesso sem depender de como os usuários serão verificados, o projeto tem alguns usuários cravados diretamente no código, para fins de simplificação mesmo.
No caso, esta é a base de usuários usada no projeto:
public static class BaseUsuarios { public static IEnumerable<Usuario> Usuarios() { return new List<Usuario> { new Usuario { Nome = "Fulano", Senha = "1234" }, new Usuario { Nome = "Beltrano", Senha = "5678" }, new Usuario { Nome = "Sicrano", Senha = "0912" } }; } }
Voltemos ao ProviderDeTokesDeAcesso. Chegou a hora de verificar usuário e senha. Percebeu que o método GrantResourceOwnerCredentials recebe um context como parâmetro? Dentro deste context estão as informações passadas pelo usuário. O que nos interessa são os parâmetros UserName e Password.
Neste caso, eu já estou fazendo uma consulta à ‘base de usuários’ e se nenhum usuário foi encontrado, já retorno com um erro.
var usuario = BaseUsuarios .Usuarios() .FirstOrDefault(x => x.Nome == context.UserName && x.Senha == context.Password); if (usuario == null) { context.SetError("invalid_grant", "Usuário não encontrado um senha incorreta."); return; }
Agora chegou a hora de criar o token que identifica o usuário.
var identidadeUsuario = new ClaimsIdentity(context.Options.AuthenticationType); context.Validated(identidadeUsuario);
Ao final, o token é gerado através do método context.Validated(). Veja a classe ProviderDeTokensDeAcesso com todo o código adicionado:



Agora, como testamos nossa WebApi com tokens de acesso? No caso, eu gosto de usar o PostMan, extensão do Google Chrome que permite testar webservices RESTFul.
Em primeiro lugar, como identificar um usuário? Faça uma requisição do tipo POST para o endereço que você configurou como endereço de fornecimento de tokens – no caso, servidor/token. No corpo (Body) da mensagem, você deve passar o nome do usuário (username), a senha (password) e o tipo de autorização (grant_type), que deve ser a constante password. Assim:

E o resultado é um arquivo Json com o token de acesso (access_token) e o prazo de validade em segundos (expires_in)!

Se você passar algum usuário inválido, receberá no Json de resposta exatamente a mensagem de erro configurada no código.

Voltemos à WebApi por um momento. Eu fiz um Controller com um método bem simples, cujo acesso se dá através do endereço servidor/api/teste – lembrando, eu não mexi nas rotas. Mas note que o método foi decorado com o atributo [Authorize]. Isso significa que ele exige alguma forma de autenticação do usuário – no nosso acesso, o token de acesso.

De volta ao Postman, se você tentar fazer uma requisição sem autorização ao recurso, receberá como resposta um Json com uma mensagem de recurso não autorizado, o que faz sentido.

Para se identificar, envie no cabeçalho (Headers) da requisição a chave Authorization e o token de acesso como valor, obrigatoriamente precedimento pela palavra Bearer – ou seja, Bearer token – e você viu como o token de acesso é grande! E agora o método é acessado normalmente!

Com isso, conseguimos implementar tokens de acesso em nova WebApi! Ela agora está mais segura e totalmente compatível com diferentes formas de acesso – aplicações desktop, aplicações mobile e websites. Até a próxima!
[]’s
Paulo Roberto