No artigo de hoje, vou mostrar em como utilizar a autenticação com oAuth2 em WebServices REST.
Antes de começarmos, esse artigo foi uma sugestão de tema enviada por Erick Landaverde. E o artigo foi redigido junto com a ajuda do grande Alison Lemes ( LinkedIn ).
Lembre-se de, no appserver.ini do REST, na seção HTTPREST, ative o SECURITY=1.
Agora vamos realizar um teste para pegar o token de acesso:
- Acesse a URL com os serviços REST, e procure pelo serviço TOKEN, clique nele para visualizar
- Ao carregar, note que é um POST, e deixe anotado o caminho dele ( /api/oauth2/v1/token )
- Abra um software para testarmos, no nosso caso iremos usar o Postman
- Adicione uma nova request, apontando para a URL, com o caminho do passo 3 na frente (e no tipo coloque como POST)
- Clique na aba Params, informe os parâmetros grant_type (informe o texto “password”), password (senha do usuário do protheus) e username (nome do usuário do protheus)
- Execute o POST, se tudo der certo, irá ser retornado o token de acesso
Agora para testarmos algum método, basta informarmos esse token do passo 6. Para isso, iremos pegar qualquer outro método para testar (nesse exemplo, irei usar um padrão, o /api/framework/v1/systemParameters ).
- No Postman, adicione uma requisição do tipo GET, e coloque a URL junto com o da api citada acima
- Clique na aba Authorization, no tipo coloque Bearer Token, e no conteúdo, coloque a chave gerada no item 6
- Agora execute a requisição, e verifique o resultado
Update 11/10/2021:
A pedido do Walter Franco, segue um exemplo de um fonte para ser usado com REST. É uma classe simples que lista as transportadoras cadastradas na tabela SA4.
//Bibliotecas
#Include "TOTVS.ch"
#Include "RESTFul.ch"
#Include "TopConn.ch"
/*
WS Rest de Exemplo para busca de Transportadoras
Usando como base oAuth2
Daniel Atilio
https://terminaldeinformacao.com
*/
WSRESTFUL wTransporte DESCRIPTION "WS de Métodos de Transporte"
//Atributos usados
WSDATA limit AS INTEGER
WSDATA page AS INTEGER
//Métodos usados
WSMETHOD GET ALL DESCRIPTION "Retorna todas as transportadoras" WSSYNTAX '/wTransporte?{limit, page}' PATH "all" PRODUCES APPLICATION_JSON
END WSRESTFUL
//Poderia ser usado o FWAdapterBaseV2(), porém a paginação foi feita manualmente
WSMETHOD GET ALL WSRECEIVE limit, page WSSERVICE wTransporte
Local lRet := .T.
Local oResponse := JsonObject():New()
Local cQuerySA4 := ""
Local nTamanho := 10
Local nTotal := 0
Local nPags := 0
Local nPagina := 0
Local nAtual := 0
//Efetua a busca dos transportadoras
cQuerySA4 := " SELECT " + CRLF
cQuerySA4 += " SA4.R_E_C_N_O_ AS SA4REC " + CRLF
cQuerySA4 += " FROM " + CRLF
cQuerySA4 += " " + RetSQLName("SA4") + " SA4 " + CRLF
cQuerySA4 += " WHERE " + CRLF
cQuerySA4 += " A4_FILIAL = '" + FWxFilial("SA4") + "' " + CRLF
cQuerySA4 += " AND SA4.D_E_L_E_T_ = '' " + CRLF
cQuerySA4 += " ORDER BY " + CRLF
cQuerySA4 += " SA4REC " + CRLF
TCQuery cQuerySA4 New Alias "QRY_SA4"
//Se não encontrar a transportadora
If QRY_SA4->(EoF())
SetRestFault(500, "Falha ao consultar transportadoras - A consulta de transportadoras nao retornou nenhuma informacao, revise os filtros")
Else
oResponse["objects"] := {}
//Conta o total de registros
Count To nTotal
QRY_SA4->(DbGoTop())
//O tamanho do retorno, será o limit, se ele estiver definido
If ! Empty(::limit)
nTamanho := ::limit
EndIf
//Pegando total de páginas
nPags := NoRound(nTotal / nTamanho, 0)
nPags += Iif(nTotal % nTamanho != 0, 1, 0)
//Se vier página
If ! Empty(::page)
nPagina := ::page
EndIf
//Se a página vier zerada ou negativa ou for maior que o máximo, será 1
If nPagina <= 0 .Or. nPagina > nPags
nPagina := 1
EndIf
//Se a página for diferente de 1, pula os registros
If nPagina != 1
QRY_SA4->(DbSkip((nPagina-1) * nTamanho))
EndIf
//Adiciona os dados para a meta
oJsonMeta := JsonObject():New()
oJsonMeta["total"] := nTotal
oJsonMeta["current_page"] := nPagina
oJsonMeta["total_page"] := nPags
oJsonMeta["total_items"] := nTamanho
oResponse["meta"] := oJsonMeta
//Percorre os transportadoras
While ! QRY_SA4->(EoF())
nAtual++
//Se ultrapassar o limite, encerra o laço
If nAtual > nTamanho
Exit
EndIf
//Posiciona a transportadora e adiciona no retorno
DbSelectArea("SA4")
SA4->(DbGoTo(QRY_SA4->SA4REC))
oJsonObj := JsonObject():New()
oJsonObj["id"] := SA4->A4_COD
oJsonObj["name"] := SA4->A4_NOME
aAdd(oResponse["objects"], oJsonObj)
QRY_SA4->(DbSkip())
EndDo
EndIf
QRY_SA4->(DbCloseArea())
//Define o retorno
Self:SetContentType("application/json")
Self:SetResponse(oResponse:toJSON())
Return lRet
Bom pessoal, por hoje é só.
Abraços e até a próxima.








Muchas Gracias ! Esto será muy útil !!!
Eu que agradeço pelo comentário Erick.
Abraços.
Olá Dan,
Realizei os passos que você apresentou aí e tô gostando mto destas séries de posts sobre o REST.
No meu ambiente, ainda não tenho o dicionário no BD, portanto este seu exemplo não funcionou completamente no meu teste, assim, pra eu poder ter certeza de que está correto o que estou fazendo aqui, eu deveria criar um outro método qualquer baseando consulta em alguma tabela existente no BD certo?
Qual o procedimento devo executar aqui pra ter o resultado positivo do teste?
Obrigado!
Waltre Franco
Bom dia Walter.
Obrigado pelo feedback.
Atualizei o artigo, e adicionei um exemplo customizado.
Grande abraço.
Olá Dan!
Depois de um pequeno ajuste na Query, pois usamos Oracle aqui e o SA4.D_E_L_E_T_ = ‘ ‘, precisa de um espaço entre as aspas, funcionou direitinho e entendi a ideia do processo.
Muito obrigado mesmo pelo feedback e dedicação em atender à minha solicitação.
Forte abraço.
Walter Franco
Eu que agradeço pelo comentário Walter.
Fico feliz em ter ajudado.
Grande abraço.
Bom dia, muito bons os seus artigos …. no seu exemplo da transportadora, nao vejo o TOKEN para validar se o usuario esta validado no sistema
Boa tarde Percy.
Obrigado pelo feedback.
No caso, usando o oAuth não é necessário validar o token via código fonte, quem fica responsável de fazer essa validação é diretamente o AppServer.
Então conforme os tópicos 7 ao 9, só precisamos informar o token obtido, e se na camada do AppServer bater a informação correta, ai que ele vai executar o método.
Grande abraço.
Post excelente, a totvs deveria te pagar por fazer esse trabalho maravilhoso.
Boa tarde Ismael.
Obrigado pelo feedback e generosidade no comentário.
Um grande abraço.
Bom dia Daniel,
Uma duvida, de posse do código do Token, como devemos informar este código dentro do advpl
Boa tarde Wanderson, tudo bem?
No caso, via AdvPL você não precisa tratar, o AppServer trata disso sozinho.
Há não ser que você queira consumir um WS REST Protheus em outra base Protheus, se for isso, ai você precisa se conectar usando a classe FWRest.
Boa Tarde Daniel,
Muito obrigado.