Autenticação OAuth2

Projeto HwGui - Biblioteca visual para Harbour/xHarbour

Moderador: Moderadores

Avatar do usuário
Adson
Usuário Nível 1
Usuário Nível 1
Mensagens: 33
Registrado em: 05 Mar 2019 10:36
Localização: GOIANIA/GO

Autenticação OAuth2

Mensagem 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
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Autenticação OAuth2

Mensagem por JoséQuintas »

Tá parecido com o que tentamos descobrir aqui:

https://pctoledo.org/forum/viewto ... =4&t=25795
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
Adson
Usuário Nível 1
Usuário Nível 1
Mensagens: 33
Registrado em: 05 Mar 2019 10:36
Localização: GOIANIA/GO

Autenticação OAuth2

Mensagem 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
Responder