Serviço RESTFul seguro com autorização e JWT Neste post, veja como adicionar segurança à requisições RESTFul 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. Os seguintes arquivos são necessários para implementação de segurança: htaccess-dist app/config/application.ini (chaves rest_...
PD
Serviço RESTFul seguro com autorização e JWT  
Neste post, veja como adicionar segurança à requisições RESTFul 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. Os seguintes arquivos são necessários para implementação de segurança:

  • htaccess-dist
  • app/config/application.ini (chaves rest_key e seed)
  • app/service/auth/ApplicationAuthenticationRestService.php
  • app/service/auth/ApplicationAuthenticationService.php
  • rest-secure.php.dist

  • O arquivo htaccess-dist deve ser renomeado para .htaccess Para o .htaccess ser lido corretamente, é necessário que o AllowOverride esteja ligado no Apache.

    Exemplo



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

    Introdução


    A segurança na requisição RESTful 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 RESTFul seguro


    Para utilizar o RESTFul seguro, em primeiro lugar é necessário substituir o servidor REST distribuído inicialmente (rest.php) pelo servidor com verificação de segurança (rest-secure.php), assim:

    # 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 RESTful 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/restful_secure_basic.php

    1. <?php
    2. require_once 'request.php';
    3. try {
    4.     // load objects by filter
    5.     $body['limit'] = '3';
    6.     $body['order'] = 'name';
    7.     $body['direction'] = 'desc';
    8.     
    9.     $location 'https://localhost/contacts/contacts';
    10.     print_rrequest($location'GET'$body'Basic 123') );
    11. }
    12. catch (Exception $e)
    13. {
    14.     echo 'Error: ' $e->getMessage();
    15. }
    16. ?>


    Neste outro exemplo, temos a mesma chamada utilizando Shell script, veja a chave de autorização sendo passada nos headers (parâmetro -H):

    #curl -X GET -H "Authorization: Basic 123" "https://localhost/contacts/contacts/1"


    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.

    Para criar um token, precisamos fazer uma requisição usando a chave básica de requisição para:

    curl -H 'Authorization: Basic 123' -i -X GET https://localhost/contacts/auth/<user>/<senha>


    Exemplo:
    curl -H 'Authorization: Basic 123' -i -X GET https://localhost/contacts/auth/admin/admin


    Para que a aplicação reconheça a rota /auth/user/password é necessário adicionar a linha a seguir no .htaccess. Esta linha irá direcionar a requisição para a classe ApplicationAuthenticationRestService.

    .htaccess:
    RewriteRule ^auth/([A-Za-z0-9]*)/([A-Za-z0-9]*)$ rest.php?class=ApplicationAuthenticationRestService&method=getToken&login=$1&password=$2&%{QUERY_STRING} [NC]


    A rota SISTEMA/auth/<user>/<senha> 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.

    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. O último argumento contém a rota RESTful que será acessada. Veja mais no artigo (www.adianti.com.br/forum/pt/view_4701?servicos-restful-no-adianti-fr).

    curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJ1c2VyaWQiOiIxIiwidXNlcm5hbWUiOiJBZG1pbmlzdHJhdG9yIiwidXNlcm1haWwiOiJhZG1pbkBhZG1pbi5uZXQiLCJleHBpcmVzIjoxNTM2NzcxOTg1fQ.YPbypdCowCcjG1gO8AZ-LyurrhYUBi9HnCyufXBRpEQ' -i -X GET https://localhost/contacts/contacts/1


    Esta requisição, além de acessar este recurso RESTful 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

    O artigo a seguir demonstra como realizar toda a operação. O primeiro request demonstra 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. 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.

    O request.php pode ser obtido neste link (https://pastebin.com/jmXjD1pw).

    1. <?php
    2. require_once 'request.php';
    3. try
    4. {
    5.     $location 'http://localhost/contacts/auth/user/user';
    6.     $token request($location'GET', [], 'Basic 123');
    7.     var_dump($token);
    8.     
    9.     $location 'http://localhost/contacts/contacts/1';
    10.     var_dump(request($location'GET', [], 'Bearer ' $token));
    11. }
    12. catch (Exception $e)
    13. {
    14.     echo 'Error: ' $e->getMessage();
    15. }
    16. ?>


    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 (1)


    ML

    Boa tarde.

    Quando sobe a aplicação pra um servidor de hospedagem, que tipo de configuração é necessária pra fazer o serviço funcionar ?

    Consigo rodar localmente minha aplicação mas estou com problemas quando subo pro servidor e tento acessar a API de um sistema externo feito em typescript.