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.