Serviços REST seguro com autorização e JWT Neste post, veja como adicionar segurança à requisições REST com autorização global ou tokens JWT no Adianti Framework. Pré-requisito Todos os arquivos deste artigo são disponíveis juntamente com o Adianti Framework Template a partir da versão 5.6. Os seguintes arquivos são necessários para implementação de segurança: app/config/application.ini (chaves rest_k...
PD
Serviços REST seguro com autorização e JWT  
Neste post, veja como adicionar segurança à requisições REST com autorização global ou tokens JWT no Adianti Framework.

Pré-requisito


Todos os arquivos deste artigo são disponíveis juntamente com o Adianti Framework Template a partir da versão 5.6. Os seguintes arquivos são necessários para implementação de segurança:

  • app/config/application.ini (chaves rest_key e seed)
  • app/service/auth/ApplicationAuthenticationRestService.php (Novo na versão 5.6)
  • app/service/auth/ApplicationAuthenticationService.php (Novo na versão 5.6)
  • rest-secure.php.dist (Novo na versão 5.6)


  • Exemplo


    Para ver uma aplicação em funcionamento com todos estes recursos, faça o download da Contacts App, disponível no site da Adianti (https://www.adianti.com.br/framework-contacts).

    Introdução


    A segurança na requisição REST no Framework pode ser tratada de duas maneiras: por meio de uma chave global (REST KEY) que autoriza qualquer requisição que a informe, ou por meio de um token JWT, que identifica o usuário tal como uma sessão.

    Assim, se realizarmos comunicação entre sistemas com operações em que o usuário (sessão) não é relevante, tal como uma integração entre registros em nível de sistemas, podemos utilizar a autorização simples global (REST KEY). Já se formos realizar uma operação entre sistemas em que o perfil do usuário é relevante, tal como em casos que o Web Service utiliza a informação do usuário logado para registrar em logs de acesso, ou mesmo restringir o acesso, a autorização baseada em token JWT deve ser utilizada.

    Servidor REST seguro


    Para utilizar o REST seguro, em primeiro lugar é necessário habilitar servidor REST distribuído inicialmente (rest-secure.php.dist), da seguinte maneira:

    # mv rest-secure.php.dist rest.php


    Autorização Global


    A primeira forma de segurança que demonstraremos é por meio de autorização global. Esta forma de segurança utilizará autorização por meio de uma chave. É uma forma simples de proteger o acesso a um recurso HTTP. A autorização é realizada enviando uma chave pelo header Authorization, do tipo Basic. Como o envio não é criptografado, garanta que esteja usando SSL no seu site/sistema. O primeiro passo é definir a chave global do REST no arquivo application.ini

    app/config/application.ini
    [general] rest_key = 123


    O exemplo a seguir demonstra como realizar a chamada de um serviço REST por meio do método request(), identificando no quarto parâmetro, a autorização, que será do tipo Basic, e em seguida conterá a chave informada, que neste caso será "123". O request.php pode ser obtido neste link (https://pastebin.com/jmXjD1pw).

    rest/rest_secure_basic.php
    1. <?php
    2. require_once 'request.php';
    3. try
    4. {
    5.     $location 'http://git/contacts/rest.php';
    6.     $parameters = array();
    7.     $parameters['class']  = 'ContactRestService';
    8.     $parameters['method'] = 'load';
    9.     $parameters['id']     = '1';
    10.     
    11.     print_rrequest($location'GET'$parameters'Basic 123') );
    12. }
    13. catch (Exception $e)
    14. {
    15.     echo 'Error: ' $e->getMessage();
    16. }
    17. ?>


    Obs: Como o envio não é criptografado, garanta que esteja usando HTTPS no seu site/sistema.


    Autenticação por token



    A segunda forma de segurança que demonstraremos é por meio de token que identifica uma sessão de usuário. O primeiro passo é configurar uma seed (semente) que será usada como chave para geração dos tokens.

    app/config/application.ini
    [general] seed = sdf76oasdif7a


    No tópico anterior, vimos como autorizar um request por meio de uma chave global. Porém, esta chave global não identifica um perfil de usuário do request, somente autoriza o request. Sempre que quisermos realizar operações entre sistemas em que o perfil do usuário é relevante (logs, restrição de acesso, etc), podemos usar a autorização baseada em um token JWT.

    O primeiro passo para usar a autorização baseada em token é criar um token. Quem cria o token é a aplicação a partir da informação do usuário e senha. Este processo funciona como uma autenticação de login que cria uma sessão para o usuário. Neste caso, no luga de criar uma sessão, criaremos um token criptografado que será passado como parâmetro em todos os requests que desejamos realizar com aquele usuário. O token contém a informação do usuário e também uma hora de expiração.

    A requisição para a ApplicationAuthenticationRestService::getToken() recebe o usuário e senha, valida e autentica este usuário. O retorno desta requisição será um token JWT. A estrutura de um token JWT pode ser analisado pelo site jwt.io. Nele, você poderá ver o conteúdo do token, como usuário e hora de expiração. Apesar de você poder visualizar informações como usuário e hora de expiração, você não consegue alterar o token e construir um novo com um usuário diferente, em virtude do algoritmo de criptografia utilizado. Ao alterar ele, parte da assinatura que o valida se tornaria inválida.


    1. <?php
    2. require_once 'request.php';
    3. try
    4. {
    5.     $location 'http://git/contacts/rest.php';
    6.     $parameters = array();
    7.     $parameters['class']    = 'ApplicationAuthenticationRestService';
    8.     $parameters['method']   = 'getToken';
    9.     $parameters['login']    = 'user';
    10.     $parameters['password'] = 'user';
    11.     
    12.     $token request($location'GET'$parameters'Basic 123');
    13.     print $token;
    14. }
    15. catch (Exception $e)
    16. {
    17.     echo 'Error: ' $e->getMessage();
    18. }
    19. ?>


    O primeiro request demonstrou como obter o token com o usuário user, senha user. Neste caso, utilizamos a autenticação básica com chave global, que é identificada pelo parâmetro de autorização (Basic 123). O token gerado é armazenado na variável $token.

    A partir do token obtido, que identifica um usuário válido já autenticado anteriormente pelo sistema, você poderá utilizá-lo em requisições posteriores, como no exemplo a seguir. O token é informado no parâmetro do HEADER Authorization, após a palavra Bearer.

    Em seguida, é realizada uma requisição para obter o registro de contato de ID 1. Nesta segunda requisição, identificamos o token de autenticação no último parâmetro (Bearer $token). Esta segunda requisição criará uma sessão de usuário (user), com base no token. Assim, toda operação no lado do servidor que dependa do perfil do usuário irá funcionar.

    1. <?php
    2. require_once 'request.php';
    3. try
    4. {
    5.     $location 'http://git/contacts/rest.php';
    6.     $parameters = array();
    7.     $parameters['class']    = 'ApplicationAuthenticationRestService';
    8.     $parameters['method']   = 'getToken';
    9.     $parameters['login']    = 'user';
    10.     $parameters['password'] = 'user';
    11.     
    12.     $token request($location'GET'$parameters'Basic 123');
    13.     
    14.     $location 'http://git/contacts/rest.php';
    15.     $parameters = array();
    16.     $parameters['class']  = 'ContactRestService';
    17.     $parameters['method'] = 'load';
    18.     $parameters['id']     = '1';
    19.     
    20.     print_rrequest($location'GET'$parameters'Bearer ' $token) );
    21. }
    22. catch (Exception $e)
    23. {
    24.     echo 'Error: ' $e->getMessage();
    25. }
    26. ?>


    Esta requisição, além de acessar este recurso REST irá criar uma sessão de usuário durante esta requisição no servidor. Assim, qualquer operação neste tempo que depende do perfil do usuário irá funcionar. Ex: TSession::getValue('login');

    O token tem uma validade, que é definida pela classe ApplicationAuthenticationRestService como sendo de 3 horas o default. Depois disso, o token se torna inútil e um erro será lançado: Token expired. This operation is not allowed

    Referências


    www.douglaspasqua.com/2016/08/21/autenticacao-em-apis-rest/
    scotch.io/tutorials/the-anatomy-of-a-json-web-token
    imasters.com.br/back-end/entendendo-o-jwt
    imasters.com.br/apis-microsservicos/restful-api-jwt-para-autenticaca

    Curso completo Meu Negócio Pronto
    Use para si, ou transforme em um negócio: Inclui aulas e códigos-fontes
    Gestor de conteúdo (SITE) + Loja Virtual (E-Commerce) + Emissor de Notas para infoprodutos


    Meu negócio pronto Quero me inscrever agora!

    Comentários (4)


    HE

    Boa noite!

    Talvez esteja sendo alguma falha minha, mas já busquei de todas as formas identificar o erro e não entendo.

    Quando utilizo o Basic para gerar o token via Postam gera um erro de autenticação, porém quando realizo a requisição de acordo os códigos disponibilizados no tutorial, roda normalmente.

    Já quando realizo a requisição via postam com Bearer utilizando o token que foi gerado no código php, funciona normalmente, porém necessito que algumas consultas sejam publicas e outras tenho que validar o usuário.

    Desde já, obrigado.
    IM

    Ja havia comentado isso ... o postman nao leva de forma certa o Authorization.
    FL

    Estou com o mesmo problema!
    Implementando pelo PHP funciona mas pelo Postman ou Insomnia dá erro de autenticação.
    Acredito ser alguma coisa relacionada com a versão do Adianti pois o aplicativo Contacts (exemplo) funciona corretamente pelo Postman.
    PC

    Pessoal, conseguiram resolver o problema de autenticação? Estou usando o FW 7.4 PHP 8.1, se puderem colocar como resolveram o problema. Até no users e contacts da o mesmo erro de autenticação.