24

私はアンドロイドの初心者で、これがアンドロイドでの最初のプロジェクトです。「認証」の問題に1日以上苦労しています。いくつかのオプションを試しましたが、どれも機能しませんでした。

基本的にはREST APIを呼び出してレスポンスを取得したい。別のiOSアプリでも同じものを使っているのでAPI的には問題ないと思います。

認証ヘッダーを渡しますが、まだ認証が見つかりませんというメッセージが表示されます。これに関連するstackoverflowに関する質問はほとんど見つかりませんでしたが、機能しないものもあれば、意味をなさないものもあります。

status code を取得します401。これは、認証に合格しなかったか、合格した場合は間違っていることを意味します。ここで、合格したものは正しいと確信しています。

以下は私のコードです:

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 のスクリーンショットを 見てください:

ログキャット

どんな助けでも大歓迎です。ありがとうございました。

4

5 に答える 5

51

WWW-Authenticateこのエラーは、サーバーが 401 (Unauthorized) を送信するが、クライアントに次に何をすべきかのヒントとなるヘッダーを提供しないために発生します。WWW-Authenticateヘッダーは、必要な認証の種類 ( Basic または Digest のいずれか) をクライアントに通知ます。これは、おそらくヘッドレス http クライアントではあまり役に立ちませんが、HTTP 1.1 RFC はそのように定義されています。WWW-Authenticateライブラリがヘッダーを解析しようとしてもできないため、エラーが発生します。

RFC から:

(...) 応答には、要求されたリソースに適用可能なチャレンジを含む WWW-Authenticate ヘッダー フィールド (セクション 14.47) が含まれている必要があります。(...)

サーバーを変更できる場合の解決策:

  • 次のような偽の「WWW-Authenticate」ヘッダーを追加しますWWW-Authenticate: Basic realm="fake"。これは単なる回避策であり、解決策ではありませんが、動作するはずであり、http クライアントは満足しています (ヘッダーに何を入れることができるかについては、こちらの説明を参照してください)。ただし、一部の http クライアントは自動的にリクエストを再試行するため、複数のリクエストが発生する可能性があることに注意してください (たとえば、間違ったログイン カウントが頻繁にインクリメントされます)。これは、iOS http クライアントで確認されました。
  • このブログでLoudvcharが提案しているように、ブラウザのポップアップ ログイン フォームのようなチャレンジに対する自動反応を避けるために、次のような非標準の認証方法を使用できます。重要な点は、を含める必要があるということです。WWW-Authenticate: xBasic realm="fake"realm
  • 403の代わりにHTTP ステータス コードを使用します401。セマンティックは同じではなく、通常、ログイン 401 を使用する場合は正しい応答ですが (詳細については、こちらを参照してください)、互換性の点でより安全なソリューションです。

サーバーを変更できない場合の解決策:

  • @ErikZ が彼の投稿に書いたように、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(); 
    }
    
  • OkHttpなどの別の HTTP クライアントを使用する

于 2014-02-03T17:54:55.033 に答える
1

テストしている Android のバージョンは何ですか?

Gingerbread の開発作業中に、Android オーセンティケーターで問題が発生しました (Android の新しいバージョンで動作が異なるかどうかはわかりません)。Fiddler2 を使用してアプリとサーバー間の HTTP トラフィックを調べたところ、HTTP 要求ごとにオーセンティケーターが認証文字列を送信していないことがわかりました。私はそれが必要でした。

代わりに、私はこれに頼りました:

urlConnection.setRequestProperty("Authorization", "Basic " + Base64.encodeToString("userid:pwd".getBytes(), Base64.NO_WRAP ));

それは私のコードからのカットアンドペーストです。urlConnection は HttpURLConnection オブジェクトであることに注意してください。

于 2013-06-15T10:47:09.130 に答える
1

KitKat 以前の Android を実行しているデバイスでも同じ問題が発生しましたが、Volley ライブラリを使用していたため、@for3st によって提供されたクライアント側の修正が機能しませんでした。Volley 用に調整する必要がありました。この問題に苦しんでいる人を助けます:

HurlStack hurlStack = new HurlStack() {
            @Override
            public HttpResponse performRequest(final Request<?> request, final Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
                try {
                    return super.performRequest(request, additionalHeaders);
                } catch (IOException e) {
                    return new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), 401, e.getMessage());
                }
            }
        };

Volley.newRequestQueue(context.getApplicationContext(), hurlStack);

このようにして 401 エラーが返され、再試行ポリシーがその仕事を実行できます (例: トークンの要求など)。IOException は 401 以外の問題が原因で発生する可能性があるため、Authorization キーワードの例外メッセージを解析することを選択し、他の問題に対しては別の応答コードを返すことができます。

于 2015-09-23T14:55:58.087 に答える