如何响应Android中的HTTP身份验证挑战

时间:2012-11-28 18:43:21

标签: android http authentication https

在我的应用中,我通过HTTPS对Web服务进行HTTP调用。我的愿望是设计我的客户端,以便在有身份验证挑战时只询问用户的用户名和密码。我希望被动,而不是抢先。由于我的应用程序的性质,在某些情况下它不需要进行身份验证。

在iOS中,通过我的应用程序的iOS版本中实现的NSURLConnectionDelegateProtocol可以轻松完成此过程。使用此类建立连接,并且仅当提出质询时,该类才会向其委托询问身份验证凭据。

如何在Android中完成此操作?使用AuthenticationHandler?或者Authenticator?如果是这样,可以提供示例或教程吗?

修改1

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

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

编辑2

虽然使用Authenticator类的示例很少或没有,但我能够找到的内容表明,在getPasswordAuthentication之内的单一方法中无法提示用户输入。可能必须恢复到Apache Http客户端......

最终修改

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

2 个答案:

答案 0 :(得分:3)

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

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

对不起,我没有任何示例代码;我已经在java.net中实现了这个,但是如果你使用的是apache,那对你没什么用。

此主题可以帮助您:Http Basic Authentication in Java using HttpClient?

编辑:

我已经在java.net中实现了这个,但这是我的工作,我没有访问源代码。一个问题是java.net不允许您基于每个连接设置身份验证,而是让您实现单个全局身份验证器。由于我的应用只与一个特定的网站进行了沟通,这不是问题。

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

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

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

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

我不确定这对Android环境有什么用处,因为弹出对话框可能不是验证器的可用选项。但我可能错了;这取决于你的申请。

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

答案 1 :(得分:2)

对于那些不知道的人,有两种主要的Http客户端API可用于Android:

  • Apache HTTP Client
  • 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方法中,提示用户输入用户名和密码,然后以某种方式返回。如果您可以提供帮助,请发布答案!