Como usar a autenticação com oAuth2 em REST

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:

  1. Acesse a URL com os serviços REST, e procure pelo serviço TOKEN, clique nele para visualizar

API de Token

  1. Ao carregar, note que é um POST, e deixe anotado o caminho dele ( /api/oauth2/v1/token )

Pegando o caminho do TOKEN

  1. Abra um software para testarmos, no nosso caso iremos usar o Postman
  2. Adicione uma nova request, apontando para a URL, com o caminho do passo 3 na frente (e no tipo coloque como POST)

Informando a URL para buscar o TOKEN

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

Definindo o usuário e senha

  1. Execute o POST, se tudo der certo, irá ser retornado o token de acesso

Pegando o token gerado

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

  1. No Postman, adicione uma requisição do tipo GET, e coloque a URL junto com o da api citada acima

Informando a URL de uma API para ser consumida

  1. Clique na aba Authorization, no tipo coloque Bearer Token, e no conteúdo, coloque a chave gerada no item 6

Informando o Token de acesso

  1. Agora execute a requisição, e verifique o resultado

Resultado da execução

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 "wTransporte"       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")
        oResponse["errorId"]  := "TRA001"
        oResponse["error"]    := "Transportadora(s) não encontrada(s)"
        oResponse["solution"] := "A consulta de transportadoras não retornou nenhuma informação"
    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.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

6 Responses

  1. Muchas Gracias ! Esto será muy útil !!!

  2. Walter Franco disse:

    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

  3. Walter Franco disse:

    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

Deixe uma resposta