Disponibilizar um modelo de autenticação e autorização de acesso a recursos (endpoints), que permita abstração e flexibilidade com a utilização de um serviço de login independente (conforme modelo de arquitetura especificado na RFC000010 e RFC000015).
OAuth2 é um protocolo que permite aos usuários ter acesso a determinados recursos sem precisar expor suas credenciais. Por isso, serão usados os fluxos de autenticação e autorização baseados no OAuth2.
Ao entrar em uma empresa com controle de acesso, é necessário efetuar previamente o cadastro na portaria (autenticação).
De acordo com a sua visita, a portaria garantirá a autorização de acesso temporária e você receberá um crachá para entrar em determinadas portas.
Independente da restrição que o crachá impõe a seus utilizadores, a ideia é clara: você dá a alguém acesso limitado as portas de acordo com a sua visita.
Análogo ao crachá, para obter acesso limitado a recursos usando o OAuth2, utiliza-se um access token (token JWT), que permite usufruir recursos de terceiros de forma segura.
A TOTVS utilizará no novo serviço de login um dos fluxos propostos pelo framework Oauth2, abaixo a sua especificidade:
Para o ERP ficar dentro da especificação e ter o escopo adequado, a TOTVS seguirá a implementação de dois modelos de autenticação:
As configurações para utilização dos conceitos de login conforme OAuth2 são realizadas nas telas de Propriedades, disponíveis no produto.
CFG - OAuth2 | Configura os modelos (Grant Type) de autenticação do usuário propostos nesta documentação. |
CFG - JWT | Configura o modelo do Token JWT que será gerado caso a autenticação seja realizada com sucesso. |
De acordo com o modelo escolhido, sua utilização consiste em duas etapas:
Autenticação: Processo que gera o token
Autorização: Processo que autoriza o token ao endpoint
OAuth2 - Resource Owner Password Credentials
O modelo Resource Owner Password Credentials pode ser utilizado em portais pois vincula o token com um usuário do ERP.
A seguir serão demonstrados alguns trechos de códigos em JavaScript e TypeScript para exemplificar uma utilização no produto. Lembrando que o código pode ser alterado de acordo com a linguagem de programação utilizada, pois é necessário seguir somente os conceitos gerais de Autenticação (para gerar o token) e Autorização (validação do token).
Após efetuar a ação do login, o mesmo deve executar o endpoint de geração do token, onde seu resultado pode ser armazenado no localStorage do navegador para utilizações posteriores.
No trecho de código abaixo, caso o token seja gerado com sucesso, seu retorno é armazenado no localStorage com a chave token-service.token.
function login_oauth2() { var http = new XMLHttpRequest(); var url = '/totvs-login-oauth2/oauth2/token?grant_type=password'; http.open('POST', url, true); http.setRequestHeader('Authorization', "Basic " + btoa($txtUsername.val()+":"+$txtPassword.val())); http.onreadystatechange = function() { if(http.readyState == 4 && http.status == 200) { localStorage.setItem("token-service.token", http.responseText); } } } |
Para limitar o uso indevido em caso de vazamentos, todos os tokens expiram (tempo parametrizável no ERP Datasul), por este motivo é importante que durante a utilização do portal os tokens sejam continuamente revalidados.
Com o intuito de facilitar a geração do token dentro do produto, é recomendado a utilização do refresh_token:
Método: POST
URL: http://{{host}}:{{port}}/totvs-login-oauth2/oauth2/token?grant_type=refresh_token
Authorization: Não informar pois é considerada somente a validação do token
Body (x-www-form-urlencoded):
|
No trecho de código abaixo é demonstrado a geração contínua de um token (com base no refresh_token), sendo executada em um ciclo continuo 60 segundos antes de sua expiração:
$scope.refreshToken = function() { var http = new XMLHttpRequest(); var url = '/totvs-login-oauth2/oauth2/token?grant_type=refresh_token'; var params = `refresh_token=${$scope.getRefreshToken()}`; http.open('POST', url, true); http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http.onreadystatechange = function() { if(http.readyState == 4 && http.status == 200) { localStorage.setItem("token-service.token", http.responseText); } } http.send(params); }; $scope.getExpiresInToken = function() { const tokenService = localStorage.getItem('token-service.token'); let jsonTokenService = JSON.parse(tokenService); return jsonTokenService['expires_in']; }; $scope.getRefreshToken = function() { const tokenService = localStorage.getItem('token-service.token'); let jsonTokenService = JSON.parse(tokenService); return jsonTokenService['refresh_token']; }; var expireIn = $scope.getExpiresInToken() * 1000; /** * 1 minuto antes de expirar o token, tenta efetuar a renovacao */ setInterval(async() => { await $scope.refreshToken() }, (expireIn - (60 * 1000))); |
Com o token disponível no localStorage e continuamente validado pelo refresh_token, para efetuar o acesso a determiados recrusos, basta resgatar o valor do access_token e envia-lo na requisição desejada.
O trecho de código abaixo demonstra o envio do token na URL devido as características deste endpoint (Smart View), porém este mesmo conceito pode ser adaptado com o modelo Authorization Bearer para acessar os endpoints do ERP Datasul.
public onSmartView(smLayout: SmartViewLayout): void { let jwtToken = this.getAccessToken(); let urlView = `${this.urlSmartView}reports/${smLayout["id"]}/view?access_token=${jwtToken}&hidemenus=true&expires_in=0&token_type=bearer`; this.link = this.sanitizer.bypassSecurityTrustResourceUrl(urlView); this.poPageSlide.open(); } private getAccessToken(): String { let tokenService = localStorage.getItem('token-service.token'); let jsonTokenService = JSON.parse(tokenService); return jsonTokenService['access_token']; } |