Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

CONTEÚDO

Informações

Índice
maxLevel4
minLevel2
indent50px
absoluteUrltrue

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. Por isso, serão usados os fluxos de autenticação e autorização baseados no OAuth2.


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 TOTVS utilizará no novo serviço de login um dos fluxos propostos pelo framework Oauth2, abaixo a sua especificidade:

  • O Grant Type para autenticação (Client Credentials ou Resource Owner Password Credentials);
  • Autorização de acesso conforme validade do token de acesso informado.

TIPOS DE GARANTIA DE ACESSO

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:

  • Client Credentials
  • Resource Owner Password Credentials



03. EXEMPLO 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.

03. EXEMPLO DE UTILIZAÇÃO

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 - OAuth2Configura os modelos (Grant Type) de autenticação do usuário propostos nesta documentação.
CFG - JWTConfigura 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 - Client Credentials

OAuth2 - Resource Owner Password Credentials

g. Resource Owner Password Credentials - Exemplos de Utilização

O modelo Resource Owner Password Credentials pode ser utilizado em portais pois vincula o token com um usuário do ERP.



Informações

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).

b. Client Credentials

Geração do token

De posse com as credenciais de acesso (Id cliente e Senha cliente) cadatradas na tela de Propriedades → OAuth2 → Client Credentials 

Login

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-serviceclient.token. 

Bloco de código
languagejs
function logintoken_client_oauth2credentials() {
	var http = new XMLHttpRequest();
	var url = '/totvs-login-oauth2/oauth2/token?grant_type=passwordclient_credentials';
	http.open('POST', url, true);

	http.setRequestHeader('Authorization', "Basic " + btoa($txtUsername.val()+<id_cliente>":"+$txtPassword.val())<senha_cliente>);

	http.onreadystatechange = function() {
		if(http.readyState == 4 && http.status == 200) {
			localStorage.setItem("token-serviceclient.token", http.responseText);
		}
	}
}

Geração dos tokens durante a utilização

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

AuthorizationNã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
titleNota
  • O refresh_token não possui atributos de acesso (aud, tenantId, scope), portanto não deve ser utilizado para acessos aos recursos;
  • Todo refresh_token é vinculado a um access_token, sendo deste token os atributos considerados para a nova geração;
  • Por motivos de segurança, após a utilização do refresh_token, o mesmo é automaticamente invalidado;
  • Para considerar um novo ciclo de geração, é necessário considerar os novos tokens gerados a partir do refresh_token.


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)));

Utilização dos tokens para acessos aos recursos

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.

Bloco de código
languagejs
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'];
}


c. Resource Owner Password Credentials

A utilização do Resource Owner Password Credentials é similar ao Client Credentials, somente difere na autenticação, onde são utilizados outro endpoint e 

Login

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. 

Bloco de código
languagejs
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);
		}
	}
}

Geração dos tokens durante a utilização

As etapas de atualização do token são identicas ao modelo anteriormente apresentado, pode ser utilizado os mesmos endpoints.


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-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)));

Utilização dos tokens para acessos aos recursos

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.

Bloco de código
languagejs
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'];
}