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

问题描述:

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

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

这怎么能在Android中完成?使用AuthenticationHandler?或者可能是Authenticator?如果是这样,可以提供示例或教程吗?

编辑1

使用验证器类(见我的回答如下),我现在能够响应身份挑战,但目前只能通过硬编码的凭据。我想提示用户输入用户名和密码。根据Android documentation,在getPasswordAuthentication方法中,“通常会提示用户输入必要的信息”。

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

编辑2

虽然有很少或使用验证器类的没有例子,我已经能够发现表明,提示输入用户从一个单一的方法中是不可能的,像getPasswordAuthentication。可能要恢复到Apache的HTTP客户端...

最后编辑

我仍在使用HttpURLConnection的,但这样做沿着爱德华什么建议以下线的东西。似乎没有任何可配置的类来处理身份验证挑战并提示用户输入,所以我正在手动执行此操作。

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

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

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

这个线程可以帮助你:Http Basic Authentication in Java using HttpClient?

编辑:

我在java.net执行这一点,但它是工作,我没有为租赁和我没有访问源代码。一个问题是,java.net不允许您在每个连接的基础上设置身份验证,而是让您实现一个全局身份验证器。由于我的应用只与一个特定网站进行通信,所以这不是问题。

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

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

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

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

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

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

+0

我也试图使用java.net,因为它似乎将成为未来最受支持的选项。我会尝试你的建议。你有没有试过使用Authenticator类? – Groppe

+0

查看我上面的编辑。 –

+0

谢谢。从我读过的内容来看,不幸的是,在Authenticator的getPasswordAuthentication方法中弹出一个对话框(我想要做的)是不可能的。 – Groppe

对于那些不知道是谁,有两个主要的HTTP客户端API的可用于安卓

  • Apache的HTTP客户端
  • java.net HttpURLConnection的

最近概述这两个这是在这Android Developers Blog post给出。

我选择使用java.net执行,因为,引述博客:“新的应用程序应该使用HttpURLConnection的;它是我们将花精力前进”此外,HttpURLConnection的将连接用如果Url提供的是HTTPS,则自动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); 
} 

的关键(对我来说),以获得实际被称为认证者的方法,是这一行:

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

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

下一步:从上面的getPasswordAuthentication方法,提示用户输入用户名和密码,并以某种方式返回它。如果你可以帮忙,发表一个答案!

+0

heh;每天学些新东西。我读过java.net被认为已经过时,已经为JavaME开发,并且每个人都应该使用Apache客户端。我只在Apache库不可用的情况下使用java.net。我想是时候切换回去了。 –

+0

爱德华,我刚刚遇到你问的问题(http://*.com/questions/6100989/java-how-to-launch-a-ui-dialog-from-another-thread-eui-dialog-from-another-thread-eg-for-authenticator) ,而且你提供的答案似乎与我现在想要做的事情相符。你在评论中说:“我希望Java有Android的消息传递工具。”既然我们现在正在谈论Android,那么你会如何推荐去做呢? – Groppe

+0

不错的工作家伙..我有一个复杂的iOS认证过程,并不知道如何在Android中做到这一点。我很惊讶没有更多的赞扬你们俩。我必须存储un/pw才能通过SSL,然后再通过Windows身份验证挑战,所以这篇文章有助于这种类型的进程。 – whyoz