【问题标题】:How to respond to HTTP authentication challenges in Android如何响应 Android 中的 HTTP 身份验证挑战
【发布时间】:2012-11-16 17:24:54
【问题描述】:

在我的应用程序中,我通过 HTTPS 对 Web 服务进行 HTTP 调用。我的愿望是设计我的客户端,使其仅在遇到身份验证挑战时询问用户的用户名和密码。我想要响应式,而不是抢占式。由于我的应用的性质,在某些情况下它不需要进行身份验证。

在 iOS 中,这个过程通过NSURLConnectionDelegateProtocol 变得非常简单,这是在我的应用程序的 iOS 版本中实现的。使用此类建立连接,并且只有在提出质询时,该类才会向其委托请求身份验证凭据。

如何在 Android 中做到这一点?使用AuthenticationHandler?或者Authenticator?如果可以,能否提供示例或教程?

编辑 1

使用 Authenticator 类(请参阅下面的答案)我现在能够响应身份验证挑战,但目前只能使用硬编码凭据。我想提示用户输入用户名和密码。根据Android documentation,在getPasswordAuthentication 方法中,您“通常会提示用户输入所需的输入”。

这怎么可能?在不阻塞 UI 线程(我知道不能/不应该完成)的情况下,如何在该方法中显示对话框、等待用户输入、然后检索输入的凭据并返回它们?

编辑 2

虽然很少或没有关于使用 Authenticator 类的示例,但我能够找到的结果表明,在单个方法中提示用户输入是不可能的,例如 getPasswordAuthentication。可能必须恢复到 Apache Http 客户端...

最终编辑

我仍在使用 HttpURLConnection,但按照 Edward 下面的建议做一些事情。似乎没有任何可配置的类来处理身份验证挑战和提示用户输入,所以我手动执行此操作。

【问题讨论】:

    标签: android http authentication https


    【解决方案1】:

    发送不带身份验证标头的请求。如果需要身份验证,连接将失败并出现 401 错误。让失败冒泡到任何代码发出初始请求。然后该代码应该向用户显示一个身份验证对话框。记住用户提供的用户名/密码,然后在请求中添加必要的身份验证标头重试失败的请求。

    记住会话其余部分的用户名/密码,这样您就不必一直询问用户。

    很抱歉,我没有任何示例代码;我已经在 java.net 中实现了这个,但是如果你使用的是 apache,那对你没有任何好处。

    这个帖子可能会对你有所帮助:Http Basic Authentication in Java using HttpClient?

    编辑:

    我已经在 java.net 中实现了这个,但这是我为雇用而做的工作,我无权访问源代码。一个问题是 java.net 不允许您在每个连接的基础上设置身份验证,而是让您实现单个全局身份验证器。因为我的应用只与一个特定的网站通信,所以这不是问题。

    我所做的是创建一个Authenticator 的子类,用于缓存用户的用户名/密码数据。缓存的初始值为空。还有一个“尝试计数器”。当验证器被调用并且没有缓存的用户/密码信息时,会通过对话框提示用户。如果缓存的值存在,它们会被返回而不会打扰用户。

    如果有后续调用验证器,则假定用户/密码信息不正确,并再次提示用户。如果计数器达到 10,则验证器返回 null(失败)。

    计数器在每次新的互联网连接之前重置。

    更智能的身份验证器会关注主机和/或领域(提示字符串)并相应地缓存用户/密码。

    我不确定这对您在 Android 环境中是否有用,因为弹出对话框可能不是您的身份验证器可用的选项。但我可能错了。这取决于您的应用程序。

    在 Android 环境中,您需要从线程执行 http 请求,然后在数据到达时向活动发出信号。如果您的线程检测到 401 错误,它将向 Activity 发出信号,然后该 Activity 会弹出一个对话框并重新启动该线程。然后,该线程将注册一个简单的身份验证器,该身份验证器仅返回用户/密码信息。或者,线程可以手动构建一个 Authorization 标头,尽管这需要更多的工作。

    【讨论】:

    • 我也在尝试使用 java.net,因为这似乎是未来最受支持的选项。我会试试你的建议。您是否尝试过使用 Authenticator 类?
    • 谢谢。根据我的阅读,不幸的是,无法从 Authenticator 的 getPasswordAuthentication 方法中弹出一个对话框(我想做的)。
    【解决方案2】:

    对于那些不知道的人,有两个主要的 Http 客户端 API 可以在 Android 中使用:

    • Apache HTTP 客户端
    • java.net HttpURLConnection

    Android Developers Blog post 中提供了这两者的最新概述。

    我选择使用 java.net 实现,因为,引用博客:“新应用程序应该使用 HttpURLConnection;这是我们未来将要花费精力的地方。”另外,如果提供的 Url 是 Https,HttpURLConnection 将使用 SSL 自动连接。正如我在原始帖子中所说,我正在寻找 API 中的一个接口,以便我能够在必要时自动处理身份验证挑战。我发现 Authenticator 类可以满足我的要求。

    这是我到目前为止的代码,它可以工作:

    URL Url = new URL(url);
    
    Authenticator.setDefault(new Authenticator () {
        protected PasswordAuthentication getPasswordAuthentication() {
            return (new PasswordAuthentication("username", "password".toCharArray()));
        }
    });
    
    connection = (HttpURLConnection) Url.openConnection();
    connection.setRequestProperty("Authorization", "Basic");
    
    content = new BufferedInputStream(connection.getInputStream());
    BufferedReader reader = new BufferedReader(new InputStreamReader(content));
    String line;
    while ((line = reader.readLine()) != null) {
        stringBuilder.append(line);
    }
    

    让 Authenticator 的方法真正被调用的关键(对我来说)是这一行:

    connection.setRequestProperty("Authorization", "Basic");
    

    否则,请求实际上会返回 200(OK)的响应,并将我重定向到登录页面。

    下一步:通过上面的getPasswordAuthentication 方法,提示用户输入用户名和密码,然后以某种方式返回。如果您对此有帮助,请发布答案!

    【讨论】:

    • 嘿;每天学些新东西。我读到 java.net 被认为是过时的,它是为 JavaME 开发的,每个人都应该使用 Apache 客户端。我只在 Apache 库不可用的情况下使用 java.net。我想是时候切换回去了。
    • Edward,我刚刚遇到了您提出的一个问题 (stackoverflow.com/questions/6100989/…),您/Andrew 提供的答案似乎与我现在正在尝试做的事情差不多。您在评论中说“我有点希望 Java 具有 Android 的消息传递功能。”既然我们现在谈论的是 Android,你会如何推荐它?
    • 干得好,伙计们..我有一个复杂的 iOS 身份验证过程,不知道如何在 Android 中进行。我很惊讶你们两个都没有更多的赞成票。我必须存储 un/pw 以传递 SSL,然后再传递 Windows 身份验证质询,所以这篇文章有助于这种类型的过程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 2013-07-05
    • 2015-06-03
    • 2012-10-14
    相关资源
    最近更新 更多