Série WebApi Parte 2 – Autenticação via token.

logo

Quando falamos de aplicações web e aplicações mobile a questão de autenticação é importante para garantir a integridade de sua implementação e segurança de seus dados, em um cenário web tradicional é amplamente utilizado o uso de cookies ou sessions para guardar  a autenticação válida durante a navegação evitando assim que seja preciso se autenticar toda a vez que tentar utilizar algum recurso protegido de um sistema.

Quando estamos falando de serviços a autenticação muda um pouco, elas não podem manter um cookie por exemplo, então recorrem a um token a cada vez que precisar acessar algum recurso protegido.

Neste artigo vou mostrar como implementar segurança via token em uma aplicação WEBAPI criada com os conceitos do OWIN (se não conhece o OWIN ainda vá ao meu artigo anterior), o OWIN já possui alguns middlewares e entre eles está o OAuth2 que serve para executar o processo de autenticação.

O protocolo OAuth2 efetua a validação e gera o token para devolução ao cliente, para isso basta efetuar um post para o endereço configurado em uma propriedade chamada TokenEndpointPath , passando no body da mensagem três parâmetros: grant_type, username e password.

No parâmetro grant_type devemos sempre passar a string “password”, ao validar essas informações o OAuth2 retorna em formato JSON um objeto que contém um token e o tempo de expiração, este tempo é determinado em sua implementação.

Com esse token em mãos você do lado do cliente deve guardar e usar nas requisições futuras até que perca a validade e você tenha que requisitar um novo.

Vamos criar uma WEBAPI nova no projeto do artigo anterior, então crie um novo projeto com o nome de WebApiToken e deixe o mesmo igual ao projeto WebApiOwin. (estes fontes já se encontram lá no github).

Depois de criar o projeto igual ao anterior e verificar que  o mesmo está rodando corretamente faça a inclusão do pacote Microsoft.Owin.Security.OAuth pelo nuget digitando no package manager console:

Install-Package Microsoft.Owin.Security.OAuth

Ao finalizar a instalação da biblioteca do OAuth, abra o arquivo Startup.cs e vamos começar a fazer algumas mudanças para efetuar a autenticação via Token:

webapitoken_image1Foi criado um método novo ConfigureAccessToken, dentro deste método vamos configurar um objeto do tipo OAuthAuthorizationServerOptions com os seguintes parâmetros:

  • AllowInsecureHttp – defina esse parâmetro como true, mas lembre-se que em produção deverá ser false;
  • TokenEndPointPath – este é o endereço que irá fornecer o token de acesso;
  • AccessTokenExpireTimeSpan – é o valor em tempo que o token irá expirar;
  • Provider – aqui vamos definir a classe que irá efetivamente validar o usuário e devolver o token.

Agora vamos criar a classe ProviderTokenAccess, para isso crie uma classe na raiz do projeto e insira o código abaixo:

webapitoken_image2Esta classe herda a classe do OAuth OAuthAuthorizationServerProvider e basta agora subscrever os dois métodos ValidateClientAuthentication e GrantResourceOwnerCredentials

Neste exemplo foi criado uma lista estática com dois usuários somente para exemplificar, para isso criei um objeto User com duas propriedades Name e Password do tipo string e inseri em uma lista estática.

O método ValidateClientAuthentication é responsável por realizar validações extras quando o usuário se autentica com o token.

Dentro do método GrantResourceOwnerCredentials que recebe o contexto você terá acesso ao usuário e a senha através dos objetos contexto.UserName e contexto.Password, com esses dados você deverá efetuar a validação em suas regras de negocio, ou no banco, ou em um Active Directory, emfim aqui a validação fica a seu critério.

Caso não encontre o usuário devemos setar o objeto contexto.SetError com uma chave/valor e sair do método.

Caso encontre emitimos o token com o objeto ClaimsIdentity e o contexto.Validated.

Agora vamos abrir a classe controller HomeController e definir no método Get() que ele agora deverá ser protegido utilizado o atributo AUTORIZE:

webapitoken_image7Com essas definições prontas, vamos tentar chamar a API no browser e se tudo correu bem deveremos receber a mensagem: “Authorization has been denied for this request”:

webapitoken_image3Isso acontece porque fizemos uma chamada a WEBAPI sem mandar um token de acesso válido.

Agora com o serviço seguro o primeiro passo para consumir seus métodos e requisitar um token, vamos lá e para isso vamos utilizar o PostMan para efetuar nossas chamadas, a imagem abaixo mostra como chamar o serviço:

webapitoken_image4Notem que foi feito um request para a url http://localhost:10275/token  esse “/token” foi o que defimos lá na propriedade TokenEndPointPath da classe Startup.cs.

Caso passe alguma informação incorreta nos parâmetros, tipo uma senha ou usuario errados, a WEBAPI deverá retornar com erro como na imagem abaixo:

webapitoken_image5Agora vamos chamar o método protegido passando o token que conseguimos na primeira chamada:

webapitoken_image6Podemos ver no resultado que o request foi efetuado com sucesso, internamente a WEBAPI validou o token enviado e devolveu a resposta corretamente.

É isso ae, agora sua camada de serviços está segura com autenticação via token, no próximo artigo sobre WEBAPI vou falar um pouco sobre CORS (Cross-Origin Resource Sharing) e acrescentar mais algumas configurações bacanas na camada de serviço.

Lembrando que todo esse código está disponível no meu github. Bons estudos a todos e se ajudou comenta ae!

Abraço.

 

 

Você pode gostar...

13 Resultados

  1. Ismael disse:

    O que deve ser feito quando o token vencer?

    • Marcelo disse:

      Ismael, você deverá ter um mecanismo no seu front-end que verifique sempre o retorno de suas API’s, caso o retorno seja de token inválido
      deverá novamente solicitar um token novo e substituir o que deixou em cache ou storage local.

  2. Reynaldo disse:

    Parabéns, único tutorial de WebApi que encontrei sem aquele monte de frescura, querendo explicar cada virgula do código! Foi direto ao ponto e consegui até que enfim entender como funciona esse negócio!
    Vlw e parabéns!

  3. Rafael disse:

    Na hora de hospedar essa Web Api em um Windows Server com IIS tem alguma diferença?

  4. Rogério disse:

    Amigo, não consigo acessar a rota “/token” que foi especificada no tutorial . Minha aplicação está rodando em localhost e quando faço http://localhost:2990/token, sempre recebo um 404 not found. Também tentei http://localhost:2990/api/token sem sucesso. A minha aplicação foi criada usando o minimo de componentes pré instalados (web api 2 vazia). Dessa forma, tive que fazer algumas configurações como a criação do arquivo Startup.cs e a sua configuração no Web.config, adicionando as seguintes keys:

    No caso Vpainel é o nome do meus namespace.
    Espero que possa me ajudar. Obrigado.

    • Marcelo disse:

      Rogério, boa noite, desculpe a demora para responder, ainda está com problemas? se sim consegue disponibilizar seu código fonte para tentar descobrir o problema? abraço

  5. Antonio disse:

    Parabéns, muito bom seu conteúdo!!!

  6. José Silva disse:

    Marcelo,

    Gostaria de saber se consigo capturar o token neste momento que está sendo invocado o método protegido?
    Usaria esta informação para identificar quem está requisitando o serviço.
    Ou teria uma outra forma?

    Abs,

  7. Diego disse:

    Como consumir essa api via código C#?
    Minha dúvida está no ponto em que no postman usa “x-www.form-urlencoded”
    e não json. Como escrever um código C# para obter o token?

  8. João Vitor Chagas disse:

    Marcelo excelente trabalho, direto e simples, ajudou muito, porem estou com algumas duvidas, eu consigo ter acesso aos dados enviados pelo Token? ‘access_token’ e ‘expires_in’.
    Caso não tenha tem alguma forma de validar se o usuário que requisitou um novo Token ainda possui um access_token valido, ou seja que ainda não esperou?, obrigado.

  9. Anderson disse:

    Parabéns Marcelo, ótimo artigo, porém estou com um porblema de autenticação, exibi a seguinte mensagem após da emissão do Token: Authorization has been denied for this request

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *