Gibt es eine einfachere Möglichkeit, den http-Client für die präemptive Basisauthentifizierung einzurichten, als mit here beschrieben?
In früheren Versionen (3.x) war dies früher ein einfacher Methodenaufruf (z. B. httpClient.getParams().setAuthenticationPreemptive(true)
).
Die Hauptsache, die ich vermeiden möchte, ist das Hinzufügen von BasicHttpContext zu jeder von mir ausgeführten Methode.
Es ist schwierig, dies zu tun, ohne jedes Mal einen Kontext durchzugehen, aber Sie können dies wahrscheinlich mit einem Request Interceptor tun. Hier ist ein Code, den wir verwenden (gefunden von JIRA, Iirc):
// Pre-emptive authentication to speed things up
BasicHttpContext localContext = new BasicHttpContext();
BasicScheme basicAuth = new BasicScheme();
localContext.setAttribute("preemptive-auth", basicAuth);
httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
(...)
static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme avaialble yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth");
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_Host);
if (authScheme != null) {
Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
if (creds == null) {
throw new HttpException("No credentials for preemptive authentication");
}
authState.setAuthScheme(authScheme);
authState.setCredentials(creds);
}
}
}
}
Wenn Sie HttpClient 4 zur Authentifizierung mit einer einzigen Anforderung zwingen möchten, funktioniert Folgendes:
String username = ...
String password = ...
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));
Dies ist die gleiche Lösung wie bei Mat's Mannion, aber Sie müssen nicht localContext für jede Anforderung angeben. Es ist einfacher, fügt jedoch ALLEN Anforderungen Authentifizierung hinzu. Nützlich, wenn Sie keine individuellen Anforderungen haben, wie in meinem Fall bei der Verwendung von Apache Solr, das intern HttpClient verwendet.
import org.Apache.http.HttpException;
import org.Apache.http.HttpHost;
import org.Apache.http.HttpRequest;
import org.Apache.http.HttpRequestInterceptor;
import org.Apache.http.auth.AuthScope;
import org.Apache.http.auth.AuthState;
import org.Apache.http.auth.Credentials;
import org.Apache.http.client.CredentialsProvider;
import org.Apache.http.client.protocol.ClientContext;
import org.Apache.http.impl.auth.BasicScheme;
import org.Apache.http.protocol.ExecutionContext;
import org.Apache.http.protocol.HttpContext;
httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
(...)
static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme available yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_Host);
Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
if (creds == null) {
throw new HttpException("No credentials for preemptive authentication");
}
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
Natürlich müssen Sie den Anmeldeinformationsanbieter festlegen:
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(url.getHost(), url.getPort()),
new UsernamePasswordCredentials(username, password))
Die Variable AuthScope
darf keinen Bereich enthalten, da dies nicht im Voraus bekannt ist.
Viele der obigen Antworten verwenden veralteten Code. Ich verwende Apache SOLRJ Version 5.0.0 . Mein Code besteht aus
private HttpSolrClient solrClient;
private void initialiseSOLRClient() {
URL solrURL = null;
try {
solrURL = new URL(urlString);
} catch (MalformedURLException e) {
LOG.error("Cannot parse the SOLR URL!!" + urlString);
throw new SystemException("Cannot parse the SOLR URL!! " + urlString, e);
}
String Host = solrURL.getHost();
int port = solrURL.getPort();
AuthScope authScope = new AuthScope(Host, port);
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword("red bananas in the spring");
String decryptPass = textEncryptor.decrypt(pass);
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, decryptPass);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
authScope,
creds);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.addInterceptorFirst(new PreemptiveAuthInterceptor());
builder.setDefaultCredentialsProvider(credsProvider);
CloseableHttpClient httpClient = builder.build();
solrClient = new HttpSolrClient(urlString, httpClient);
}
Der PreemptiveAuthInterceptor lautet nun wie folgt:
static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
// If no auth scheme available yet, try to initialize it
// preemptively
if (authState.getAuthScheme() == null) {
CredentialsProvider credsProvider = (CredentialsProvider)
context.getAttribute(HttpClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_Host);
AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
Credentials creds = credsProvider.getCredentials(authScope);
if(creds == null){
}
authState.update(new BasicScheme(), creds);
}
}
}
Ich denke, der beste Weg ist, es einfach manuell zu machen. Ich habe die folgende Funktion hinzugefügt
import javax.xml.bind.DatatypeConverter;
...
private static void addAuthHeader(HttpRequestBase http, String username, String password) throws UnsupportedEncodingException {
String encoded = DatatypeConverter.printBase64Binary((username + ":" + password).getBytes("UTF-8"));
http.addHeader("AUTHORIZATION", "Basic " + encoded);
}
HTTPRequestBase
kann eine Instanz von HttpGet
oder HttpPost
sein
import Android.util.Base64;
...
private static void addAuthHeader(HttpRequestBase http, String username, String password) throws UnsupportedEncodingException {
String encoded = Base64.encodeToString((username + ":" + password).getBytes("UTF-8"), Base64.NO_WRAP);
http.addHeader("AUTHORIZATION", "Basic " + encoded);
}
Ein wenig zu spät zur Party, aber ich kam durch den Thread und versuchte, dies für die Proxy-Vorautorisierung einer Post-Anfrage zu lösen. Zu Adams Antwort kam noch Folgendes hinzu:
HttpPost httppost = new HttpPost(url);
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
Header bs = new BasicScheme().authenticate(creds, httppost);
httppost.addHeader("Proxy-Authorization", bs.getValue());
Ich denke, das könnte für alle anderen hilfreich sein, die auf dieses Problem stoßen.
Ich verwende diesen Code, basierend auf meinem Lesen von des HTTPClient 4.5-Dokuments :
HttpClientContext ctx = HttpClientContext.create()
ctx.setCredentialsProvider(new BasicCredentialsProvider())
ctx.setAuthCache(new BasicAuthCache())
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user, pass)
AuthScope authScope = new AuthScope(Host, port)
ctx.getCredentialsProvider.setCredentials(authScope, credentials)
// This part makes authentication preemptive:
HttpHost targetHost = new HttpHost(Host, port, scheme)
ctx.getAuthCache.put(targetHost, new BasicScheme())
... und stellen Sie sicher, dass Sie diesen Kontext immer an HTTPClient.execute()
übergeben.
Ich verstehe deinen abschließenden Kommentar nicht ganz. Es ist der HttpClient, der über all diese Maschinerie verfügt, um preemptive auth durchzuführen, und Sie müssen dies nur einmal tun (wenn Sie Ihren HttpClient erstellen und konfigurieren). Sobald Sie das getan haben, konstruieren Sie Ihre Methodeninstanzen auf dieselbe Weise wie immer. Sie fügen der Methode nicht "BasicHttpContext" hinzu.
Ich denke, Ihre beste Wette besteht darin, Ihr eigenes Objekt zu haben, das den gesamten für präemptive Auth erforderlichen Junk einrichtet und eine oder mehrere einfache Methoden zum Ausführen von Anforderungen für bestimmte HTTPMethod-Objekte enthält.
in Android kann Mat Mannions Antwort https nicht auflösen, senden Sie immer noch zwei Anfragen.
public static DefaultHttpClient createProxyHttpClient() {
try {
final DefaultHttpClient client = createPlaintHttpClient();
client.setRoutePlanner(new HttpRoutePlanner() {
@Override
public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
boolean isSecure = "https".equalsIgnoreCase(target.getSchemeName());
if (needProxy) {
Header header = isSecure ? ProxyUtils.createHttpsAuthHeader() : ProxyUtils.createAuthHeader();
if (isSecure) {
client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT + "\r\n" + header.getName() + ":" + header.getValue());
} else {
client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT);
if (request instanceof RequestWrapper) {
request = ((RequestWrapper) request).getOriginal();
}
request.setHeader(header);
}
String Host = isSecure ? ProxyUtils.SECURE_Host : ProxyUtils.Host;
int port = isSecure ? ProxyUtils.SECURE_PORT : ProxyUtils.PORT;
return new HttpRoute(target, null, new HttpHost(Host, port), isSecure);
} else {
client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT);
return new HttpRoute(target, null, isSecure);
}
}
});
return client;
} catch (Exception e) {
e.printStackTrace();
return new DefaultHttpClient();
}
}
public static DefaultHttpClient createPlaintHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
PlainSSLSocketFactory socketFactory = new PlainSSLSocketFactory(trustStore);
socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
BasicHttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 30000);
HttpConnectionParams.setSoTimeout(params, 30000);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", socketFactory, 443));
ThreadSafeClientConnManager ccm = new ThreadSafeClientConnManager(params, registry);
HttpClientParams.setCookiePolicy(params, CookiePolicy.BROWSER_COMPATIBILITY);
final DefaultHttpClient client = new DefaultHttpClient(ccm, params);
client.setRoutePlanner(new HttpRoutePlanner() {
@Override
public HttpRoute determineRoute(HttpHost target, HttpRequest arg1, HttpContext arg2) throws HttpException {
client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, com.netease.cloudmusic.utils.HttpRequest.USER_AGENT);
return new HttpRoute(target, null, "https".equalsIgnoreCase(target.getSchemeName()));
}
});
return client;
} catch (Exception e) {
e.printStackTrace();
return new DefaultHttpClient();
}
}