到目前为止我有这个代码:
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的路径和在?
中读取服务器响应请帮助我了解如何正确执行此操作。
谢谢!
答案 0 :(得分:5)
我已设法使用OkHttp进行摘要式身份验证。在这个代码示例中,我还使用了Dagger和Robospice-retrofit。我所做的是创建一个OkHttp Authenticator并将其分配给我的自定义OkHttp客户端。
authenticator类实现了一个身份验证方法,只要服务器遇到401错误并且需要返回 Authorization 标头(如果它需要 Proxy-),它就会被调用授权您应该实现 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());
}
}
答案 1 :(得分:3)
您可能想切换到HttpURLConnection
。根据{{3}},其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 :(得分:2)
Android附带的Apache HttpClient
版本为based on an old, pre-BETA version of HttpClient
。 Google有long recommended against using it和removed it in Android 6.0。谷歌的替代HttpURLConnection
does not support HTTP digest authentication,只是基本的。
这为您提供了一些选项,包括:
HttpURLConnection
(如Google建议的那样)并使用库bare-bones-digest进行摘要式身份验证。示例如下。HttpURLConnection
或HttpClient
。 OkHttp不支持开箱即用的摘要,但是实现了摘要验证器的库okhttp-digest。示例如下。HttpClient
,明确将'org.apache.http.legacy'
库添加到您的版本中,如changelist for Android 6.0中所述。HttpClient
移植到Android,但该项目已停止使用。详细了解Apache's page on HttpClient for Android。以下是如何使用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-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();