java.io.IOException :未发现身份验证挑战 [英] java.io.IOException : No authentication challenges found

查看:41
本文介绍了java.io.IOException :未发现身份验证挑战的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 android 的新手,这是我在 android 上的第一个项目.我为身份验证"问题苦苦挣扎了一天多.我尝试了几种选择,但都没有奏效.

I am newbie to android and this is my first project on android. I am struggling with "authentication" problem for more than a day. I tried several options but none of them worked.

基本上,我想调用 REST API 并获得响应.我确信 API 没有问题,因为我在另一个 iOS 应用程序中使用了相同的 API.

Basically, I want to call a REST API and get response. I am sure that there is no problem in API as I use the same one in another iOS application.

我通过了授权标头,但仍显示未找到消息的身份验证.我在 stackoverflow 上发现了一些与此相关的问题,但其中一些没有用,而另一些对我来说没有意义.

我得到状态代码 401.我知道这意味着要么没有通过身份验证,要么如果通过了,那么他们就错了.在这里,我确定我通过的那些是正确的.

I pass authorization header but still authentication no found message is shown. I found few question on stackoverflow related to this, but some of them did not work and some does not make sense to me.

I get status code 401. I know this means either no authentication passed or if passed, then they are wrong. Here, I am sure my passed ones are correct.

下面是我的代码:

try {
    url = new URL(baseUrl);
}
catch (MalformedURLException me) {
     Log.e(TAG, "URL could not be parsed. URL : " + baseUrl + ". Line : " + getLineNumber(), me);
     me.printStackTrace();
}

try {
    urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setRequestMethod(method); 
    urlConnection.setConnectTimeout(TIMEOUT * 1000);
    urlConnection.setChunkedStreamingMode(0);

    // Set HTTP headers                 
    String authString = "username:password";
    String base64Auth = Base64.encodeToString(authString.getBytes(), Base64.DEFAULT);
    urlConnection.setRequestProperty("Authorization", "Basic " + base64Auth);
    urlConnection.setRequestProperty("Accept", "application/json");
    urlConnection.setRequestProperty("Content-type", "application/json");

    if (method.equals("POST") || method.equals("PUT")) {
        // Set to true when posting data
        urlConnection.setDoOutput(true);

        // Write data to post to connection output stream
        OutputStream out = urlConnection.getOutputStream();
        out.write(postParameters.getBytes("UTF-8"));
    }

    try {
        // Get response
        in = new BufferedInputStream(urlConnection.getInputStream());
    }
    catch (IOException e) {
        Log.e(TAG, "Exception in getting connection input stream. in : " + in);
                    e.printStackTrace();
    }

    // Read the input stream that has response
    statusCode = urlConnection.getResponseCode();
    Log.d(TAG, "Status code : " + statusCode);
}
catch (ProtocolException pe) {
    pe.printStackTrace();
}
catch (IllegalStateException ie) {
    ie.printStackTrace();
}
catch (IOException e) {
    e.printStackTrace();
}   
finally {
    urlConnection.disconnect();
}


查看 logcat 的屏幕截图:

任何帮助将不胜感激.谢谢.

Any help would be appreciated. Thank you.

推荐答案

发生此错误是因为服务器发送了 401 (Unauthorized) 但没有给出 WWW-Authenticate 标头,提示客户端下一步要做什么.WWW-Authenticate 标头告诉客户端需要哪种身份验证(BasicDigest).这在无头 http 客户端中可能不是很有用,但这就是 定义了 HTTP 1.1 RFC.发生错误是因为 lib 尝试解析 WWW-Authenticate 标头但不能.

This error happens because the server sends a 401 (Unauthorized) but does not give a WWW-Authenticate header which is a hint to the client what to do next. The WWW-Authenticate header tells the client, which kind of authentication is needed (either Basic or Digest). This is probably not very useful in headless http clients, but that's how the HTTP 1.1 RFC is defined. The error occurs because the lib tries to parse the WWW-Authenticate header but can't.

来自 RFC:

(...)响应必须包含一个 WWW-Authenticate 头域(部分14.47) 包含适用于所请求资源的挑战.(...)

(...)The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource.(...)

如果您可以更换服务器,可能的解决方案:

Possible solutions if you can change the server:

  • 添加一个虚假的WWW-Authenticate"标头,例如:WWW-Authenticate: Basic realm="fake".这仅仅是一种解决方法而不是解决方案,但它应该可以工作并且 http 客户端满意(请参阅此处讨论您可以在标题中放置的内容).但请注意,某些 http 客户端可能会自动重试请求,从而导致多个请求(例如,错误的登录计数增加过于频繁).这是在 iOS http 客户端上观察到的.
  • 正如 loudvchar本博客 为避免像浏览器中弹出登录表单那样自动响应挑战,您可以使用非标准的身份验证方法,如下所示:WWW-Authenticate: xBasic realm=假的".重要的一点是必须包含 realm.
  • 使用 HTTP 状态代码 403 而不是 401.它的语义不一样,通常在使用登录时 401 是正确的响应 (有关详细讨论,请参见此处),但在兼容性方面是更安全的解决方案.
  • Add a fake "WWW-Authenticate" header like: WWW-Authenticate: Basic realm="fake". This is a mere workaround not a solution, but it should work and the http client is satisfied (see here a discussion of what you can put in the header). But beware that some http clients may automatically retry the request resulting in multiple requests (e.g. increments the wrong login count too often). This was observed with the iOS http client.
  • As proposed by loudvchar in this blog to avoid automatic reactions to the challenge like a pop-up login form in a browser, you can use a non-standard authentication method like so: WWW-Authenticate: xBasic realm="fake". The important point is that the realm has to be included.
  • Use HTTP status code 403 instead of 401. It's semantic is not the same and usually when working with login 401 is a correct response (see here for a detailed discussion) but the safer solution in terms of compatibility.

如果您无法更改服务器的可能解决方案:

Possible solutions if you can't change the server:

  • 正如@ErikZ 在他的post 你可以使用 try&catch

  • As @ErikZ wrote in his post you could use a try&catch

HttpURLConnection connection = ...;
try {
    // Will throw IOException if server responds with 401.
    connection.getResponseCode(); 
} catch (IOException e) {
    // Will return 401, because now connection has the correct internal state.
    int responsecode = connection.getResponseCode(); 
}

  • 使用不同的 http 客户端,如 OkHttp

    这篇关于java.io.IOException :未发现身份验证挑战的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆