Нужна помощь в создании дайджест-аутентификации для Android - PullRequest
3 голосов
/ 28 февраля 2012

Пока у меня есть этот код:

private class DownloadWebPageTask extends AsyncTask<String, Void, String> 
{
        @Override
        protected String doInBackground(String... theParams) 
        {
            String myUrl = theParams[0];
            String myEmail = theParams[1];
            String myPassword = theParams[2];

            HttpPost post = new HttpPost(myUrl);
            post.addHeader("Authorization","Basic "+ Base64.encodeToString((myEmail+":"+myPassword).getBytes(), 0 ));
            ResponseHandler<String> responseHandler = new BasicResponseHandler();

            String response = null;

            try 
            {
                    response = client.execute(post, responseHandler);
                InputStream content = execute.getEntity().getContent();

                BufferedReader buffer = new BufferedReader(
                            new InputStreamReader(content));
                    String s = "";
                    while ((s = buffer.readLine()) != null) 
                    {
                        response += s;
                    }
                } 
                catch (Exception e) 
                {
                    e.printStackTrace();
                }

            return response;
        }


        @Override
        protected void onPostExecute(String result) 
        {
            }

}

Этот код не компилируется, потому что я нахожусь в замешательстве из-за:

                response = client.execute(post, responseHandler);
                InputStream content = execute.getEntity().getContent();

Я получил этот код от работыс различными примерами, и не уверен, каким Object должен быть клиент, и будет ли первая строка просто получать ответ сервера, или мне нужно идти по пути получения InputStream и чтения ответа сервера в?

Пожалуйста, помогите мне понять, как сделать это правильно.

Спасибо!

Ответы [ 3 ]

5 голосов
/ 10 июля 2014

Мне удалось использовать дайджест-проверку подлинности с использованием OkHttp . В этом примере кода я также использую Dagger и Robospice-retrofit. Я создал OkHttp Authenticator и назначил его своему клиенту OkHttp.

Класс authenticator реализует метод authenticate , который будет вызываться всякий раз, когда сервер обнаружит ошибку 401 и ожидает Authorization back header (если он ожидает Proxy-Authorization Вы должны реализовать метод authenticateProxy .

Что он в основном делает, так это оборачивает вызовы в HttpClient DigestScheme и делает его пригодным для OkHttp. В настоящее время это не увеличивает счетчик nc. Это может вызвать проблемы с вашим сервером, так как это может быть интерпретировано как атака воспроизведения.

public class DigestAuthenticator implements com.squareup.okhttp.Authenticator {
    @Inject DigestScheme mDigestScheme;
    @Inject org.apache.http.auth.Credentials mCredentials;

    @Override
    public Request authenticate(Proxy proxy, Response response) throws IOException {
        String authHeader = buildAuthorizationHeader(response);
        if (authHeader == null) {
            return null;
        }
        return response.request().newBuilder().addHeader("Authorization", authHeader).build();
    }

    @Override
    public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
        return null;
    }

    private String buildAuthorizationHeader(Response response) throws IOException {
        processChallenge("WWW-Authenticate", response.header("WWW-Authenticate"));
        return generateDigestHeader(response);
    }

    private void processChallenge(String headerName, String headerValue) {
        try {
            mDigestScheme.processChallenge(new BasicHeader(headerName, headerValue));
        } catch (MalformedChallengeException e) {
            Timber.e(e, "Error processing header " + headerName + " for DIGEST authentication.");
        }
    }

    private String generateDigestHeader(Response response) throws IOException {
        org.apache.http.HttpRequest request = new BasicHttpRequest(
                response.request().method(),
                response.request().uri().toString()
        );

        try {
            return mDigestScheme.authenticate(mCredentials, request).getValue();
        } catch (AuthenticationException e) {
            Timber.e(e, "Error generating DIGEST auth header.");
            return null;
        }
    }
}

Затем аутентификатор будет использоваться в OkHttpClient, созданном с провайдером:

public class CustomClientProvider implements Client.Provider {
    @Inject DigestAuthenticator mDigestAuthenticator;

    @Override
    public Client get() {
        OkHttpClient client = new OkHttpClient();
        client.setAuthenticator(mDigestAuthenticator);
        return new OkClient(client);
    }
}

Наконец, клиент настроен на сервер RetrofitRobospice в функции createRestAdapterBuilder :

public class ApiRetrofitSpiceService extends RetrofitJackson2SpiceService {
    @Inject Client.Provider mClientProvider;

    @Override
    public void onCreate() {
        App.get(this).inject(this);
        super.onCreate();
        addRetrofitInterface(NotificationRestInterface.class);
    }

    @Override
    protected String getServerUrl() {
        return Constants.Url.BASE;
    }

    @Override
    protected RestAdapter.Builder createRestAdapterBuilder() {
        return super.createRestAdapterBuilder()
                .setClient(mClientProvider.get());
    }
}
3 голосов
/ 28 февраля 2012

Возможно, вы захотите переключиться на HttpURLConnection.Согласно этой статье его API проще, чем HttpClient, и лучше поддерживается на Android.Если вы решите использовать HttpURLConnection, аутентификация будет довольно простой:

Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("username", "password".toCharArray());
    }
});

После этого продолжайте использовать HttpURLConnection как обычно.Простой пример:

final URL url = new URL("http://example.com/");
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
final InputStream is = conn.getInputStream();
final byte[] buffer = new byte[8196];
int readCount;
final StringBuilder builder = new StringBuilder();
while ((readCount = is.read(buffer)) > -1) {
    builder.append(new String(buffer, 0, readCount));
}
final String response = builder.toString();
2 голосов
/ 20 октября 2016

Версия Apache HttpClient, поставляемая с Android, основана на старой версии до 100% HttpClient, предшествующей бета-версии.Google долгое время рекомендовал против использования , а удалил его в Android 6.0 .Замена Google HttpURLConnection не поддерживает дайджест-проверку подлинности HTTP , только базовая.

Это оставляет вам несколько вариантов, в том числе:

  • Миграция на HttpURLConnection (как рекомендует Google) и использовать библиотеку bare-bones-digest для дайджест-аутентификации.Пример ниже.
  • Используйте библиотеку OkHttp вместо HttpURLConnection или HttpClient.OkHttp не поддерживает дайджест из коробки, но есть библиотека okhttp-digest , которая реализует дайджест-аутентификатор.Пример ниже.
  • Продолжайте использовать (устарело) HttpClient, явно добавляя библиотеку 'org.apache.http.legacy' в свою сборку, как указано в списке изменений для Android 6.0 .
  • Существует проект Apache для переноса новых версий HttpClient на Android, но проект был прекращен.Подробнее о Страница Apache на HttpClient для Android .
  • Реализация HTTP-дайджеста самостоятельно.

Вот подробный пример того, как аутентифицировать запрос с использованием bare-bones-digest и HttpURLConnection (скопировано со страницы проекта github):

// Step 1. Create the connection
URL url = new URL("http://httpbin.org/digest-auth/auth/user/passwd");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

// Step 2. Make the request and check to see if the response contains
// an authorization challenge
if (connection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
    // Step 3. Create a authentication object from the challenge...
    DigestAuthentication auth = DigestAuthentication.fromResponse(connection);
    // ...with correct credentials
    auth.username("user").password("passwd");

    // Step 4 (Optional). Check if the challenge was a digest
    // challenge of a supported type
    if (!auth.canRespond()) {
        // No digest challenge or a challenge of an unsupported
        // type - do something else or fail
        return;
    }

    // Step 5. Create a new connection, identical to the original
    // one..
    connection = (HttpURLConnection) url.openConnection();
    // ...and set the Authorization header on the request, with the
    // challenge response
    connection.setRequestProperty(
        DigestChallengeResponse.HTTP_HEADER_AUTHORIZATION,
        auth.getAuthorizationForRequest("GET", connection.getURL().getPath()));
}

Вот пример использования OkHttp и okhttp-digest (скопировано со страницы дайджеста okhttp):

client = new OkHttpClient();
final DigestAuthenticator authenticator = new DigestAuthenticator(new Credentials("username", "pass"));

final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();
client.interceptors().add(new AuthenticationCacheInterceptor(authCache));
client.setAuthenticator(new CachingAuthenticatorDecorator(authenticator, authCache));

Request request = new Request.Builder()
  .url(url);
  .get()
  .build();
Response response = client.newCall(request).execute();
...