我非常感谢任何可以帮助我解决问题的帮助。
从Excel VBA代码我需要下载&从HTTPS站点https://redmine.itransition.com/解析CSV文件。我尝试使用WinHTTP来获取文件。但是,我无法理解为什么身份验证不起作用。以下是相关代码:
TargetURL = "https://redmine.itransition.com/projects/pmct/time_entries.csv"
Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1")
HTTPReq.Option(4) = 13056 ' WinHttpRequestOption_SslErrorIgnoreFlags 13056: ignore all err, 0: accept no err
HTTPReq.Open "GET", TargetURL, False
HTTPReq.SetCredentials "UN", "PW", 0
HTTPReq.send
返回以下响应(仅列出某些字符串):
Content-Type: text/html; charset=utf-8
Status: 406
X-Runtime: 5
但是,如果我使用
成功进行手动验证后从Firefox cookie发送“Cookie”字符串HTTPReq.setRequestHeader "Cookie", SetCookieString
HTTPReq.send
我很容易得到预期的文件。当然,我对这种解决方案不满意,并希望执行真正的WinHTTP身份验证。但是,我无法理解我的代码中出错了什么或错过了什么。我很可能必须使用.SetClientCertificate
方法,但这对我来说还不清楚 - 需要哪个证书?
或者,更一般:我应该使用哪些WinHTTP方法或函数进行调试,以找出哪个步骤阻塞/不正确并阻止我进行正确的身份验证?我花了两周时间通过MSDN和各种资源寻求帮助,但仍然没有解决方案。
提前感谢您的建议!
答案 0 :(得分:6)
以上的@Alex K.响应正是我所寻找的那么久! 在Firebug和MSDN的帮助下,我完成了3个请求:
以下代码正在按预期工作:
Set RegX_AuthToken = CreateObject("VBScript.RegExp")
' Below Pattern w/o double-quotes encoded: (?:input name="authenticity_token" type="hidden" value=")(.*)(?:")
RegX_AuthToken.Pattern = "(?:input name=" & Chr(34) & "authenticity_token" & Chr(34) & " type=" & Chr(34) & "hidden" & Chr(34) & " value=" & Chr(34) & ")(.*)(?:" & Chr(34) & ")"
RegX_AuthToken.IgnoreCase = True
RegX_AuthToken.Global = True
TargetURL = "https://redmine.itransition.com/login"
Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1")
HTTPReq.Open "GET", TargetURL, False
HTTPReq.Send
Set Token_Match = RegX_AuthToken.Execute(HTTPReq.ResponseText)
AuthToken = Token_Match.Item(0).SubMatches.Item(0)
PostData = "authenticity_token=" & AuthToken & "&back_url=https://redmine.itransition.com/" & "&username=" & UN & "&password=" & PW & "&login=Login »"
HTTPReq.Open "POST", TargetURL, False
HTTPReq.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
HTTPReq.Send (PostData)
SetCookieString = HTTPReq.GetResponseHeader("Set-Cookie")
TargetURL = "https://redmine.itransition.com/projects/pmct/time_entries.csv"
HTTPReq.Open "GET", TargetURL, False
HTTPReq.setRequestHeader "Cookie", SetCookieString
HTTPReq.Send
以下网址有助于构建POST请求:http://tkang.blogspot.com/2010/09/sending-http-post-request-with-vba.html
您需要加载没有凭据的页面,抓住看起来像 来自生成的形式&的volatile字段authenticity_token。岗位 这与用户名和&密码到/登录。
Alex K. - 再次感谢这个精彩的建议! (:
答案 1 :(得分:3)
https://redmine.itransition.com/上的登录只是一个发布用户名&的HTML表单。密码到/login
的脚本。
这与基于服务器的身份验证方案(如basic / digest / ntlm)设计的SetCredentials
不兼容。
您需要在没有凭据的情况下加载该页面,从生成的表单中获取类似于volatile字段authenticity_token
的内容。发布与用户名和&密码到/login
。
如果它是基于会话的系统,它将使用您需要在后续请求中使用的set-cookie标头+数据进行响应。
答案 2 :(得分:0)
还有一件事(除上述解决方案外),在使用类似于上述代码的POST请求时应该注意:出于某些不明原因,我仍然有4-5次(甚至更多)来自网站的讨厌的406响应,这意味着在我的情况下身份验证不完整。经过几个小时的逐步调试后,我很高兴地找到了原因:auth令牌值可能有+
个标志,并且通过分析几十个auth令牌/响应代码的箭头,我发现+
- 包含令牌与406码完全匹配。
解决方案变得非常明显:为+
安全地对PostData
进行网址编码。在http://www.blooberry.com/indexdot/html/topics/urlencoding.htm的帮助下,我终于找到了以下内容:
PostData = "authenticity_token=" & Replace(AuthToken, "+", "%2B", vbTextCompare) & _
"&back_url=https://redmine.itransition.com/projects/" & Trim(RedmineProject) & _
"/time_entries" & "&username=" & UN & "&password=" & PW & "&login=Login »"
+
被%2B
替换,这就是 - 不再是406s!)
其他特殊字符在我的情况下并不重要,但是吸取了教训。希望这能为其他人节省几个小时的生命!