4

到目前为止我有这个代码:

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();

我通过修改各种示例获得了该代码,并且不确定客户端应该是什么对象,以及第一行是否只会让我得到服务器响应,或者我必须走获取 InputStream 并读取服务器的路线回应?

请帮助我了解如何正确执行此操作。

谢谢!

4

3 回答 3

5

我已经设法使用OkHttp使用 Digest 身份验证。在这个代码示例中,我还使用了 Dagger 和 Robospice-retrofit。我所做的是创建一个OkHttp Authenticator并将其分配给我的自定义 OkHttp 客户端。

验证器类实现了一个authenticate方法,只要服务器遇到 401 错误并期望返回一个Authorization标头,就会调用该方法(如果它期望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);
    }
}

最后,在函数createRestAdapterBuilder中将客户端设置为 RetrofitRobospice 服务器:

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());
    }
}
于 2014-07-10T08:56:58.183 回答
3

您可能想要切换到HttpURLConnection. 根据这篇文章,它的 API 比HttpClient's 更简单,并且在 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();
于 2012-02-28T15:32:09.857 回答
3

HttpClientAndroid 附带的 Apache 版本基于旧的HttpClient. Google长期以来一直建议不要使用它,并在 Android 6.0 中将其删除。谷歌的替代品HttpURLConnection 不支持 HTTP 摘要认证,只支持基本的。

这为您提供了一些选择,包括:

  • 迁移到HttpURLConnection(如谷歌推荐的那样)并使用一个库,bare-bones-digest,进行摘要身份验证。下面的例子。
  • 使用OkHttp库而不是HttpURLConnectionor HttpClient。OkHttp 不支持开箱即用的摘要,但是有一个库okhttp-digest实现了摘要身份验证器。下面的例子。
  • 如Android 6.0的更改列表中所述,通过将库HttpClient显式添加到您的构建中继续使用(已弃用)。'org.apache.http.legacy'
  • 有一个用于将较新版本的 Android 移植HttpClient到 Android 的 Apache 项目,但该项目已停止。在Apache 的 HttpClient for Android 页面上阅读更多信息。
  • 自己实现 HTTP 摘要。

这是一个详细的示例,说明如何使用bare-bones-digestHttpURLConnection(从项目的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()));
}

这是一个使用OkHttpokhttp-digest的示例(从 okhttp-digest 页面复制):

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();
于 2016-10-20T06:42:10.593 回答