Página 1 de 1

Autenticação OAuth2

Enviado: 11 Ago 2021 08:16
por Adson
Olá, senhores(as):

Estou implementando uma integração com uma API que usa o método de autenticação OAuth2 e não estou tendo sucesso.

Detalhes da API:

"A comunicação com a API é realizada utilizando os padrões de arquitetura REST, trafegando mensagens no padrão JSON em codificação UTF-8.
Para que os retornos de erro estejam em formato adequado para leitura, padrão JSON, é necessário enviar o Header Accept: application/json"


Alguém tem um exemplo, usando o xHarbour para disponibilizar ?

Esse é o método que uso para fazer a conexão (As variáveis cURL, cClientID e cClientSecret são devidamente preenchidas no método construtor. A variável cTipo, contém o comando PUT/GET):

Código: Selecionar todos

METHOD Comunica() CLASS TMetodosAPI

LOCAL oServer, nPos := 0, cJSon

   // Definição do arquivo JSon com as credenciais
   cJSon := '{' +;
            '"grant_type":"client_credentials",' +;
            '"scope":"partner_all",' +;
            '"client_id":'      + AspaDupla( ::cClientID )      + ',' +;
            '"client_secret":'  + AspaDupla( ::cClientSecret )  +;
            '}'

   oServer:=CreateObject( "MSXML2.ServerXMLHTTP")
   oServer:Open( ::cTipo, ::cUrl, .F. )
   oServer:SetRequestHeader("accept", "application/json")
   oServer:setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")

   TRY
      oServer:Send(cJson)
      oServer:WaitForResponse( 1000 )
   CATCH
      ::nCode := 503
      Return
   END
   
   ::nCode := oServer:status
   
   hb_jsonDecode( oServer:ResponseBody, @::aResultado )
   
   Return

Autenticação OAuth2

Enviado: 11 Ago 2021 13:07
por JoséQuintas
Tá parecido com o que tentamos descobrir aqui:

https://pctoledo.org/forum/viewto ... =4&t=25795

Autenticação OAuth2

Enviado: 30 Ago 2021 08:20
por Adson
Consegui resolver o problema da comunicação
O código ficou assim:

Código: Selecionar todos

CLASS TClasseHTTP
********************************************************************************

   DATA cURL            INIT ""
   DATA cClientID       INIT ""
   DATA cClientSecret   INIT ""
   DATA aResultado      INIT Hash()
   DATA cTokenTemp      INIT ""                // Token provisório
   DATA cTokenType      INIT ""                // Token provisório
   DATA tTokenExpira    INIT CTOT("")          // Data e hora que o token expira
   DATA cPedido         INIT ""                // Número do pedido
   DATA nStatusPed      INIT 0                 // Código do status do pedido
   DATA cStatusPed      INIT ""                // Descrição do status to pedido
   DATA cMetodoPed      INIT ""                // Descrição do método para atualizar o pedido (received, invoiced, tracking, trancking-steps, canceled)
   DATA cJSonFile       INIT ""                // Arquivo JSon que contém as informações enviadas
   DATA nCode           INIT ""                // Código de retorno
   DATA cMsg            INIT ""                // Mensagem de retorno
   DATA cTipo           INIT ""                // Tipo de comunicação PUT/GET/POST
   DATA cServico        INIT ""                // Tipo de serviço a ser acessado
   DATA lSalvaRet       INIT .F.               // Indica se é pra salvar o retorno ou não

   METHOD New() CONSTRUCTOR

   METHOD LimparOfertas()
   METHOD EnviarOfertas()
   METHOD BaixarPedidos()
   METHOD EnviarPedidos()
   
   METHOD ObterToken()
   METHOD GetPostAPI()

ENDCLASS

********************************************************************************
METHOD New() CLASS TClasseHTTP
********************************************************************************

   ::cURL            := ALLTRIM(USER->FA_URL)
   ::cClientID       := ALLTRIM(USER->FA_ID)
   ::cClientSecret   := ALLTRIM(USER->FA_SECRET)
   ::aResultado      := Hash()
   ::cTokenTemp      := ""
   ::cTokenType      := ""
   ::tTokenExpira    := CTOT("")
   ::cPedido         := ""
   ::nStatusPed      := 0
   ::cStatusPed      := ""
   ::cMetodoPed      := ""
   ::cJSonFile       := ""
   ::nCode           := ""
   ::cMsg            := ""
   ::cTipo           := ""
   ::cServico        := ""
   ::lSalvaRet       := .T.
   
RETURN( SELF )

*********************************************************************************
*
*  Limpa todas as ofertas disponíveis no site.
*
*********************************************************************************
METHOD LimparOfertas() CLASS TClasseHTTP

   If DATETIME() >= ::tTokenExpira
      ::ObterToken()
   EndIf   

   If !EMPTY( ::cTokenTemp )

      ::cServico := "/partner/v1/settings/reset-offers"
      ::cTipo    := "GET"
      ::GetPostAPI()

   EndIf   

   Return

*********************************************************************************
*
*  Envia a oferta do produto (pode enviar lote de 1000 registros)
*
*********************************************************************************
METHOD EnviarOfertas() CLASS TClasseHTTP

   If DATETIME() >= ::tTokenExpira
      ::ObterToken()
   EndIf   

   If !EMPTY( ::cTokenTemp )

      ::cServico := "/partner/v1/offer/ean"
      ::cTipo    := "PUT"
      ::GetPostAPI()

   EndIf   
 
   Return

*********************************************************************************
*
*  Baixa pedidos por situação
*
*********************************************************************************
METHOD BaixarPedidos() CLASS TClasseHTTP

   If DATETIME() >= ::tTokenExpira
      ::ObterToken()
   EndIf   

   If !EMPTY( ::cTokenTemp )

      ::cServico := "/partner/v1/order/list/"+ALLTRIM(STR(::nStatusPed))
      ::cTipo    := "GET"
      ::GetPostAPI()

   EndIf   

Return

*********************************************************************************
*
*  Envia informações do pedido pro portal
*
*********************************************************************************
METHOD EnviarPedidos() CLASS TClasseHTTP

LOCAL vCorpo := ""

   vJSonFile := ""
   
   If DATETIME() >= ::tTokenExpira
      ::ObterToken()
   EndIf   

   If !EMPTY( ::cTokenTemp )

      ::cServico  := "/partner/v1/order/" + ::cPedido + '/' + ::cMetodoPed
      ::cTipo     := "PUT"

      If ::cMetodoPed == "tracking"

         vCorpo :=  '"courier_title": "proprio",' +;
                    '"tracking_code": "",' +;
                    '"tracking_url": "", ' +;
                    '"finished": true'

      ElseIf ::cMetodoPed == "invoiced"

         vCorpo := '"invoice_number":'  + AspaDupla( FA_PEDCAB->NR_NOTAVEN )                     + ',' +;
                   '"invoice_url":'     + AspaDupla( ObtemURLConsulta( FA_PEDCAB->SG_UF, '1' ) ) + ',' +;
                   '"invoice_key":'     + AspaDupla( FA_PEDCAB->NR_CHNFE )                       + ',' +;
                   '"invoice_value":'   + AspaDupla( ALLTRIM(STR(FA_PEDCAB->VR_LIQPED,10,2)) )

      EndIf

      If !EMPTY( vCorpo )
         vJSonFile   := STRZERO( HB_RandomInt( 999999 ), 6 )+".JSON"
         ::cJSonFile := vpUserDir+"\ENV_"+vJSonFile
         vCorpo := '{' + vCorpo + '}'
         MemoWrit( ::cJSonFile, vCorpo, .F. )
      EndIf

      ::GetPostAPI()

      If ::nCode = 200 .AND. FILE( ::cJSonFile )
         FErase( ::cJSonFile )
      EndIf

   EndIf
   
   Return



*******************************************************
*
* Obtém um novo token.
*
*******************************************************
METHOD ObterToken() CLASS TClasseHTTP

LOCAL oServer, nPos := 0, cCredentials, nExpireTime := 0
   
   ::cTokenTemp   := ""
   ::cTokenType   := ""
   ::tTokenExpira := CTOT("")
   ::aResultado   := Hash()
   ::nCode        := 0
   
   oServer:=CreateObject( "MSXML2.ServerXMLHTTP" )

   oServer:Open( "POST", ::cURL + "/oauth2/token", .F. )
   oServer:setRequestHeader( "Content-Type",    "application/x-www-form-urlencoded; charset=utf-8")
   oServer:SetRequestHeader( "accept",          "*/*" )
   oServer:SetRequestHeader( "Accept-Encoding", "gzip, deflate, br" )
   oServer:SetRequestHeader( "Connection",      "keep-alive" )
   
   cCredentials := "client_id=" + ::cClientID + ;
                   "&client_secret=" + ::cClientSecret + ;
                   "&grant_type=client_credentials" + ;
                   "&scope=partner_all"

   TRY
      oServer:Send(cCredentials)
      oServer:WaitForResponse( 1000 )
   CATCH
      FA_GravarLog( "OBTÉM TOKEN TRY CATCH (FALHA)" + LF + valtoprg( oServer:ResponseBody ) )
      MsgExclamation("Falha ao obter um novo token de acesso (TRY CATCH)"+LF+LF+;
                     "Tente novamente mais tarde", PROCNAME() )
      Return
   END
   
   ::nCode := oServer:status
   nPos    := aScan( aCode, {|x| x[1] == ::nCode } )
   
   If nPos > 0
      ::cMsg  := aCode[nPos,2]
   Else
      ::cMsg  := 'CÓDIGO DE RETORNO NÃO ENCONTRADO '+STR(::nCode,3)
   EndIf
   
   hb_jsonDecode( oServer:ResponseBody, @::aResultado )

   // Salva o retorno 
   If ::lSalvaRet
      If EMPTY( vJSonFile )
         vJSonFile := STRZERO( HB_RandomInt( 999999 ), 6 )+".JSON"
      EndIf   
      MemoWrit(vpUserDir+"\RET_TOKEN_"+vJSonFile, oServer:ResponseText, .F.)
   Endif

   If HHasKey(::aResultado,'access_token')
      ::cTokenTemp := ::aResultado['access_token']
   endif

   If HHasKey(::aResultado,'token_type')
      ::cTokenType := ::aResultado['token_type']
   endif

   If HHasKey(::aResultado,'expires_in')
      nExpireTime := ::aResultado['expires_in']
   endif

   // Salva as informações do token obtido
   If !EMPTY( ::cTokenTemp )
      ::tTokenExpira := DATETIME() + ( nExpireTime/24/60/60 )
   Else
      FA_GravarLog( "OBTÉM TOKEN (FALHA)" + LF + valtoprg( oServer:ResponseBody ) )
      MsgExclamation("Falha ao obter um novo token de acesso"+LF+LF+;
                     STR(::nCode,3)+" - "+::cMsg, PROCNAME() )
   EndIf

   Return

********************************************************************************
*
*  Executa métodos PUT/GET/POST usando o token
*
********************************************************************************
METHOD GetPostAPI() CLASS TClasseHTTP
********************************************************************************
LOCAL oServer, nPos := 0, cJSon

   ::aResultado := HASH()
   
   oServer:=CreateObject( "MSXML2.ServerXMLHTTP" )
   oServer:Open( ::cTipo, ::cUrl + ::cServico, .F. )
   oServer:setRequestHeader( "Content-Type",    "application/json" )
   oServer:SetRequestHeader( "Authorization",   ::cTokenType+" "+::cTokenTemp )   

   // Antes de executar o método, o arquivo JSon é salvo no caminho apontado por ::cJSonFile
   If !EMPTY( ::cJSonFile )
      cJSon := MemoRead( ::cJSonFile )
   EndIf

   TRY
      oServer:Send( cJSon )
      oServer:WaitForResponse( 1000 )
   CATCH
      MemoWrit(vpUserDir+"\RET_"+::cTipo+"_CATCH_"+vJSonFile, oServer:ResponseBody, .F.)
      ::nCode := 503
      nPos    := aScan( aCode, {|x| x[1] == ::nCode } )
      ::cMsg  := aCode[nPos,2]
      return
   END

   ::nCode := oServer:status
   nPos    := aScan( aCode, {|x| x[1] == ::nCode } )

   If nPos > 0
      ::cMsg := aCode[nPos,2]
   Else
      ::cMsg := 'CÓDIGO DE RETORNO NÃO ENCONTRADO '+STR(::nCode,3)
   EndIf

   hb_jsonDecode( oServer:ResponseBody, @::aResultado )
   
   // Salva o retorno 
   If ::lSalvaRet
      If EMPTY( vJSonFile )
         vJSonFile := STRZERO( HB_RandomInt( 999999 ), 6 )+".JSON"
      EndIf   
      MemoWrit(vpUserDir+"\RET_"+::cTipo+"_"+vJSonFile, oServer:ResponseText, .F.)
   EndIf
   
   Return