使用 Windows 对话框登录 Box
本文演示了如何通过在对话框窗口中输入凭据来登录 Box 等云存储,而不是在网页中进行登录。
引言
许多云存储提供商,如 www.box.com,使用一种身份验证机制,该机制会将您重定向到一个网页以输入您的凭据。如果您开发基于 Web 的应用程序,这是自然的做法,但对于桌面应用程序或 Windows 应用商店应用,您可能希望提供自己的登录屏幕,如果是桌面应用程序,则该屏幕将是 Windows 窗体。
我在论坛上搜索了解决此问题的方法,但未能找到端到端的解决方案。然而,一些帖子引导我找到了我将在本文中介绍的解决方案。
我描述的方法适用于 Box API 的 1.0 版本。他们刚刚发布了 2.0 版本,该版本中的身份验证机制现在使用 OAuth 2.0,但我描述的当前机制仍然有效。
注意:您需要注册成为 Box.com 的开发者,因为此代码需要一个 API_KEY,您在注册后即可获得。这是一个免费过程。此代码使用已停产的免费库 BoxSync,该库用 C# 实现 Box API v1。
使用 WebClient 进行 Web 表单提交
我最初的解决方案是通过在对话框中放置一个 IE 控件并将 Box 登录屏幕的 URL 传递给它来在 Windows 对话框中输入凭据。此解决方案的缺点是,一旦网页显示登录成功,您仍然需要按对话框的“确定”按钮。
Box 的支持告诉我,他们没有使用用户名/密码进行用户身份验证的 API,所以我寻找一种解决方案,即通过 C# 程序自动提交身份验证表单来自动登录。毕竟,浏览器是建立在 HTTP 协议之上的,程序可以通过 WebRequest
或 WebClient
等类来访问这些协议。
我找到了一些有用的帖子,演示了如何使用 WebClient
客户端提交表单,但不仅仅是传递数据给提交调用,对于像 Box 这样的实际身份验证协议,您需要确切地了解当您单击“登录”时他们向服务器提交了哪些数据。
用于向 Box 提交登录表单的最终代码如下。
public bool AuthenticateUser(string ticket, string userName, string password, out string requestToken) { bool authSuccess = false; requestToken = string.Empty; string url = string.Format("http://www.box.net/api/1.0/auth/{0}", ticket); // Use a WebRequest to process the login Stream respStream = ExecuteREST_Request(url, Method.GET); StreamReader reader = new StreamReader(respStream); string responseText = reader.ReadToEnd(); requestToken = ExtractRequestToken(responseText); using (WebClient webClient = new WebClient()) { try { NameValueCollection formFields = new NameValueCollection(); formFields.Add("login", userName); formFields.Add("password", password); formFields.Add("_pw_sql", ""); formFields.Add("remember_login", "on"); formFields.Add("__login", "1"); formFields.Add("dologin", "1"); formFields.Add("reg_step", ""); formFields.Add("submit1", "1"); formFields.Add("folder", ""); formFields.Add("skip_framework_login", "1"); formFields.Add("login_or_register_mode", "login"); formFields.Add("new_login_or_register_mode", ""); formFields.Add("request_token", requestToken); webClient.Proxy = null; string actionUrl = string.Format("https://www.box.net/api/1.0/auth/{0}", ticket); byte[] result = webClient.UploadValues(actionUrl, METHOD_POST, formFields); string htmlText = ASCIIEncoding.ASCII.GetString(result); if (CheckAuthenticated(htmlText)) { authSuccess = true; } else { requestToken = ExtractRequestToken(htmlText); authSuccess = false; } } catch (WebException ex) { Trace.WriteLine(ex.Message); } } return authSuccess; }
如果您查看此代码,特别是准备提交请求参数的部分,您会注意到除了用户名和密码之外,还有许多其他参数。
这就是问题的有趣之处,当您想使用 WebClient
等提交特定表单时,您需要确切地知道按下提交按钮时提交请求包含什么!
分析提交请求
您需要做的第一步是分析包含登录表单的网页的源代码。从该源代码中,您将提取用于发布数据的 URL。您可以在表单的 Action 中找到此 URL。对于 Box,URL 如下。
https://www.box.net/api/1.0/auth/<ticket>
ticket 是一个标识字符串,您在与 Box 初始化身份验证过程时获得。
一旦您有了提交表单的 URL,您就需要识别所有需要与请求一起传递的参数。您可以通过查看页面的源代码来识别它们,但这可能不容易重建请求,在身份验证的情况下,哪怕是一个小错误都足以导致失败。
我使用了一个 HTTP 调试工具来查看发送到服务器的确切请求。我找到的工具是 Fiddler Web Debugger,您可以在其网页上下载。这个工具非常有用,因为它能够监视 HTTPS 请求,这正是我需要做的,因为 Box 的登录 URL 是 HTTPS 的。
使用配置为监视 HTTPS 流量的 Fiddler,我可以看到提交到 Box 服务器进行身份验证的确切请求内容。我看到除了用户/密码之外还有许多其他字段,其中一个特别吸引了我的注意。该字段是 request_token,其值是一个字符串 token,每次登录都不同。幸运的是,我很容易在页面源代码中找到该值设置的位置,它位于一段脚本中。我编写了一个简单的方法来从登录页面提取该值,并使用它来构建参数。
此身份验证方法的最后一步是检查身份验证是否成功。您需要再次分析提交请求的响应才能了解结果。在操作成功时返回的页面中,我发现了以下字符串,它提供了正确的信息:api_auth_success
。
因此,当我提交表单时,我只需检查该字符串是否存在于响应页面中,然后我就可以决定是否成功。