2

*最后更新

我需要有关使用 API 验证到https://connect.garmin.com/signin/的帮助。我正在使用 VBA 和 Power Query 自动从我的 Garmin 帐户收集锻炼数据。据我所知,该网站使用基于 cookie 的身份验证和 CSRF 令牌。

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

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

我试图按照这个问题的 OmegaStripes 回答来处理 cookie, 如何在 VBA 中设置和获取 JSESSIONID cookie

在 Postman 或 VBA 中是否有处理 CSRF 令牌的特殊方法MSXML2.ServerXMLHTTP?我对 cookie 身份验证有什么根本不了解的地方吗?

如果您需要我提供任何进一步的信息,请告诉我。任何帮助是极大的赞赏!

我修改后的 OmegaStripes 代码如下,

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

编辑

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

getCookie = objIE.document.Cookie

我尝试了另一个 OmegaStripes 答案(巧合地)从 Internet Explorer 中检索所有 cookie,但没有成功。

任何有关如何使用 MSXML2.ServerXMLHTTP、IE 实例或任何其他方法的建议将不胜感激!

4

0 回答 0