Versões comparadas
Chave
- Esta linha foi adicionada.
- Esta linha foi removida.
- A formatação mudou.
CONTEÚDO
| Informações | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
01. Visão Geral
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).
02. Conceitos Aplicados
OAuth2 é um protocolo que permite aos usuários ter acesso a determinados recursos sem precisar expor suas credenciais.
Como funciona
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.
Para que serve
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.
Tipos de Concessão de Acesso
A geração e acesso ao endpoint será concedido de acordo com a especificidade do modelo OAuth2:
- O Grant Type para autenticação (Client Credentials ou Resource Owner Password Credentials);
- Autorização de acesso conforme validade do token de acesso e regras de seguranças interna (certificado, audiência e escopo).
03. Exemplos de Utilização
| Dica |
|---|
Antes de iniciar a implementação, verifique qual o modelo é o mais adequado para as concessões de acesso, com base no melhor modelo de segurança, Consulte os links: OAuth2 - Client Credentials e OAuth2 - Resource Owner Password Credentials para mais informações. |
a. Configuraçã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. |
| Informações |
|---|
A seguir serão demonstrados alguns trechos de códigos em JavaScript e TypeScript que exemplificam os conceitos gerais de Autenticação (para gerar o token) e Autorização (validação do token ao requisitar um endpoint). Lembrando que o código deve ser alterado de acordo com a linguagem de programação e regras específicas de segurança. |
b. Client Credentials
| Nota |
|---|
Este modelo é recomendado quando há a necessidade de comunicações machine-to-machine pois não há um vínculo do usuário do ERP Datasul com a requisição, consequentemente não ocorrerá alguns relacionamentos como o direcionamento do broker, setar um usuário e empresa na memória do PASOE, entre outros. |
Geração do token
De posse com as credenciais de acesso (Id cliente e Senha cliente) cadatradas na tela de Propriedades → OAuth2 → Client Credentials, pode-se efetuar a requisição para a geração dos tokens.
No trecho de código abaixo, caso o token seja gerado com sucesso, seu retorno é armazenado no localStorage (para uso posterior) com a chave token-client.token.
| Bloco de código | ||
|---|---|---|
| ||
function token_client_credentials() {
var http = new XMLHttpRequest();
var url = '/totvs-login-oauth2/oauth2/token?grant_type=client_credentials';
http.open('POST', url, true);
http.setRequestHeader('Authorization', "Basic " + <id_cliente>":"+<senha_cliente>);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
localStorage.setItem("token-client.token", http.responseText);
}
}
} |
Utilização dos tokens para acessos aos endpoints
Com o token disponível no localStorage, para efetuar o acesso a determiados endpoints, basta resgatar o valor do access_token e envia-lo na requisição desejada.
Para acessar os endpoints do ERP Datasul, basta enviar o valor do token como Authorization Bearer na requisição.
| Bloco de código | ||
|---|---|---|
| ||
public onIntegration(): void {
let jwtToken = this.getAccessToken();
...
<EFETUA A REQUISIÇÃO AO ENDPOINT, O TOKEN DEVE SER ENVIADO COM BEARER AUTHORIZATION>
...
}
private getAccessToken(): String {
let tokenService = localStorage.getItem('token-client.token');
let jsonTokenService = JSON.parse(tokenService);
return jsonTokenService['access_token'];
} |
Expiração do token
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, é necessário a utilização do refresh_token (grant_type e 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):
- refresh_token (Obrigatório): Enviar como x-www-form-urlencoded, o refresh_token gerado no login do produto.
| Nota | ||
|---|---|---|
| ||
|
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:
| Bloco de código |
|---|
$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-client.token", http.responseText);
}
}
http.send(params);
};
$scope.getExpiresInToken = function() {
const tokenService = localStorage.getItem('token-client.token');
let jsonTokenService = JSON.parse(tokenService);
return jsonTokenService['expires_in'];
};
$scope.getRefreshToken = function() {
const tokenService = localStorage.getItem('token-client.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))); |
c. Resource Owner Password Credentials
| Nota |
|---|
Este modelo é recomendado caso o endpoint requisitado necessite de informações do usuário do ERP Datasul. A utilização do Resource Owner Password Credentials é similar ao Client Credentials, somente difere na geração do token (autenticação), onde são utilizados outros parametros e um usuário e senha do ERP Datasul. |
Geração do token
Considere as credenciais de acesso de um usuário do ERP Datasul para a geração do token.
No trecho de código abaixo, caso o token seja gerado com sucesso, seu retorno é armazenado no localStorage com a chave token-service.token.
| Bloco de código | ||
|---|---|---|
| ||
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);
}
}
} |
Utilização dos tokens para acessos aos endpoints
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 uma integração com o Smart View (no qual necessita de dados do usuário do ERP Datasul para efetuar o compartilhamento dos layouts por usuário ou grupo).
O envio do token é enviado pela URL devido as características deste endpoint (Smart View), porém este mesmo conceito pode ser adaptado com o modelo Authorization Bearer (recomendado) para efetuar a integração com outros Portais ou Apps.
| Bloco de código | ||
|---|---|---|
| ||
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'];
} |
Expiração do token
As etapas de atualização do token são identicas ao modelo apresentado anteriormente (Client Credentials), no qual deve ser utilizado os mesmos endpoints.