65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Windows 对话框登录 Box

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2012年12月19日

CPOL

5分钟阅读

viewsIcon

23547

downloadIcon

518

本文演示了如何通过在对话框窗口中输入凭据来登录 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 协议之上的,程序可以通过 WebRequestWebClient 等类来访问这些协议。

我找到了一些有用的帖子,演示了如何使用 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

因此,当我提交表单时,我只需检查该字符串是否存在于响应页面中,然后我就可以决定是否成功。

结论

此代码仅适用于 Box 登录表单,但是,您可以将此方法应用于您需要通过程序提交的任何表单。没有简单的方法可以使此代码通用,因为您需要分析表单的源代码,即使在某些情况下可以完全自动化,但在 Box 的情况下,由于该字段由脚本执行设置,因此会比较困难。此方法的另一个限制是,它取决于页面构建者使用的方法。如果他们更改了页面中的某些内容,此代码将不再有效。因此,如果登录突然不起作用了,那么他们很可能在提交请求的格式上做了一些更改。

关注点

我花了一些时间来收集所有知识来完成这个简单的登录窗口以登录到 Box 帐户,所以我认为 CodeProject 的许多读者会发现这个简单的代码很有用。
© . All rights reserved.