Vba 使用Cookie身份验证和CSRF令牌连接到Web API

Vba 使用Cookie身份验证和CSRF令牌连接到Web API,vba,session-cookies,csrf,msxml,api-authorization,Vba,Session Cookies,Csrf,Msxml,Api Authorization,*最后更新 我需要使用API进行身份验证的帮助。 我正在使用VBA和Power Query从我的Garmin帐户自动收集训练数据。据我所知,该网站使用基于cookie的身份验证和CSRF令牌 我正在Postman中测试API调用,在VBA中构建身份验证请求,并使用经过身份验证的cookie在Power Query中执行数据收集。(我会对整个项目使用powerquery,但它无法返回响应头/经过验证的cookie) 在发出身份验证POST请求之前,我试图通过从响应头收集cookie和从HTML主体

*最后更新

我需要使用API进行身份验证的帮助。 我正在使用VBA和Power Query从我的Garmin帐户自动收集训练数据。据我所知,该网站使用基于cookie的身份验证和CSRF令牌

我正在Postman中测试API调用,在VBA中构建身份验证请求,并使用经过身份验证的cookie在Power Query中执行数据收集。(我会对整个项目使用powerquery,但它无法返回响应头/经过验证的cookie)

在发出身份验证POST请求之前,我试图通过从响应头收集cookie和从HTML主体收集CSRF令牌来复制浏览器操作,但我没有取得多大成功。当我尝试使用此方法进行身份验证时,响应状态为200,响应主体是带有“出错”消息的登录页面

我试着按照这个问题的答案来处理饼干,

在Postman或VBA
MSXML2.ServerXMLHTTP
中是否有处理CSRF令牌的特殊方法?关于cookie身份验证,是否有一些我根本不了解的地方

如果你需要我提供更多的信息,请告诉我。非常感谢您的帮助

我的代码修改版本如下:

Option Explicit

Sub GetCookie()

    Dim sUrl, sRespHeaders, sRespText, aSetHeaders, aList, aSetBody, sCSRFToken, sBody

    sBody = "username=USERNAME&password=PASSWORD&embed=false&_csrf="

    ' get cookie 1
    sUrl = "https://connect.garmin.com/signin/"
    XmlHttpRequest "GET", sUrl, Array(), "", sRespHeaders, sRespText
    ParseResponse "^Set-(Cookie): (\S*?=\S*?);[\s\S]*?$", sRespHeaders, aSetHeaders

    ' get cookie 2 and CSRF Token
    sUrl = "https://sso.garmin.com/sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&webhost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&source=https%3A%2F%2Fconnect.garmin.com%2Fsignin%2F&redirectAfterAccountLoginUrl=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&redirectAfterAccountCreationUrl=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso&locale=en_US&id=gauth-widget&cssUrl=https%3A%2F%2Fconnect.garmin.com%2Fgauth-custom-v1.2-min.css&privacyStatementUrl=https%3A%2F%2Fwww.garmin.com%2Fen-US%2Fprivacy%2Fconnect%2F&clientId=GarminConnect&displayNameShown=false&consumeServiceTicket=false&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=false&generateNoServiceTicket=false&globalOptInShown=true&globalOptInChecked=false&connectLegalTerms=true&locationPromptShown=true&showPassword=true"
    XmlHttpRequest "GET", sUrl, aSetHeaders, "", sRespHeaders, sRespText
    ' parse project names
    ParseResponse "^Set-(Cookie): (\S*?=\S*?);[\s\S]*?$", sRespHeaders, aSetHeaders
    sCSRFToken = GetCSRFToken("name=" & Chr(34) & "_csrf" & Chr(34) & " value=" & Chr(34), sRespText)

    ' get authenticated cookies
    sUrl = "https://sso.garmin.com/sso/signin?service=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&webhost=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&source=https%3A%2F%2Fconnect.garmin.com%2Fsignin%2F&redirectAfterAccountLoginUrl=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&redirectAfterAccountCreationUrl=https%3A%2F%2Fconnect.garmin.com%2Fmodern%2F&gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso&locale=en_US&id=gauth-widget&cssUrl=https%3A%2F%2Fconnect.garmin.com%2Fgauth-custom-v1.2-min.css&privacyStatementUrl=https%3A%2F%2Fwww.garmin.com%2Fen-US%2Fprivacy%2Fconnect%2F&clientId=GarminConnect&displayNameShown=false&consumeServiceTicket=false&generateExtraServiceTicket=true&generateTwoExtraServiceTickets=false&generateNoServiceTicket=false&globalOptInShown=true&globalOptInChecked=false&connectLegalTerms=true&locationPromptShown=true&showPassword=true"
    XmlHttpRequest "POST", sUrl, aSetHeaders, sBody & sCSRFToken, sRespHeaders, sRespText
    ' parse project names
    ParseResponse "^Set-(Cookie): (\S*?=\S*?);[\s\S]*?$", sRespHeaders, aSetHeaders

End Sub

Sub XmlHttpRequest(sMethod, sUrl, aSetHeaders, sPayload, sRespHeaders, sRespText)
    Dim aHeader
    With CreateObject("MSXML2.ServerXMLHTTP")
        '.SetOption 2, 13056 ' SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS
        .Open sMethod, sUrl, False
        For Each aHeader In aSetHeaders
            .SetRequestHeader aHeader(0), aHeader(1)
        Next
        .Send (sPayload)
        sRespHeaders = .GetAllResponseHeaders
        sRespText = .ResponseText
    End With
End Sub

Sub ParseResponse(sPattern, sResponse, aData)
    Dim oMatch, aTmp, sSubMatch
    If IsEmpty(aData) Then
        aData = Array()
    End If
    With CreateObject("VBScript.RegExp")
        .Global = True
        .MultiLine = True
        .Pattern = sPattern
        For Each oMatch In .Execute(sResponse)
            If oMatch.SubMatches.Count = 1 Then
                PushItem aData, oMatch.SubMatches(0)
            Else
                aTmp = Array()
                For Each sSubMatch In oMatch.SubMatches
                    PushItem aTmp, sSubMatch
                Next
                PushItem aData, aTmp
            End If
        Next
    End With
End Sub

Function GetCSRFToken(sPattern, sResponse)
    Dim lStart, lLength, sSubMatch

    lStart = InStr(1, sResponse, sPattern) + Len(sPattern)
    lLength = InStr(lStart, sResponse, Chr(34)) - lStart
    GetCSRFToken = Mid(sResponse, lStart, lLength)

End Function

Sub PushItem(aList, vItem)
    ReDim Preserve aList(UBound(aList) + 1)
    aList(UBound(aList)) = vItem
End Sub

编辑

我改变了创建InternetExplorer实例的方法,并自动化了登录过程。不理想,但我能够成功登录。我现在的问题是,我无法检索维护登录会话所需的HttpOnly Cookie

getCookie=objIE.document.Cookie

我尝试了另一个答案(巧合),但没有成功


如果您对如何使用MSXML2.ServerXMLHTTP、IE实例或任何其他方法实现此功能有任何建议,我们将不胜感激

尝试在禁用重定向的情况下发出请求以检索令牌和Cookie,如。感谢您的建议@omegastripes,我将试一试。@omegastripes禁用重定向似乎不起作用。我开始认为问题可能是每个请求都在重新计算csrf令牌。可能吗?有没有一种方法可以保持打开的连接以模拟使用MSXML调用的浏览器?您可以在“网络”选项卡上的“浏览器开发人员工具”中看到,网站没有使用“保持活动”,并且令牌没有更改。检查那里的请求时,我还注意到还有一些其他的请求被记录下来,VBA代码中缺少这些请求可能会影响登录过程。