Herstellen einer Verbindung zu einer Remote-URL, für die eine Authentifizierung mit Java erforderlich ist


125

Wie verbinde ich mich mit einer Remote-URL in Java, für die eine Authentifizierung erforderlich ist? Ich versuche einen Weg zu finden, den folgenden Code zu ändern, um programmgesteuert einen Benutzernamen / ein Passwort eingeben zu können, damit kein 401 ausgelöst wird.

URL url = new URL(String.format("http://%s/manager/list", _host + ":8080"));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();

Antworten:


134

Sie können den Standardauthentifizierer für http-Anforderungen wie folgt festlegen:

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

Wenn Sie mehr Flexibilität benötigen, können Sie sich auch den Apache HttpClient ansehen , der Ihnen mehr Authentifizierungsoptionen (sowie Sitzungsunterstützung usw.) bietet.


4
Wie gehen Sie mit einem schlechten Authentifizierungsereignis um? [Wenn der Benutzer beispielsweise Anmeldeinformationen für die Authentifizierung mit Benutzername und Kennwort angibt, die mit nichts übereinstimmen]?
SK9

2
Der obige Code funktioniert, ist aber ziemlich implizit, was los ist. Dort finden Unterklassen und Methodenüberschreibungen statt. Stöbern Sie in den Dokumenten für diese Klassen, wenn Sie wissen möchten, was los ist. Der Code hier ist expliziter javacodegeeks
Fuchida

12
Ist es möglich, bestimmte Authenticatorpro bestimmten URL.openConnection()Aufruf festzulegen, anstatt sie global festzulegen?
Yuriy Nakonechnyy

@ Yura: nein. Es muss global sein. Sie können jedoch böse Dinge tun, z. B. einen globalen Authentifikator festlegen, der die Anmeldeinformationen aus threadlokalen Variablen abruft, und die Anmeldeinformationen pro Thread festlegen, bevor die HTTP-Verbindung hergestellt wird.
David gegeben

4
Als Antwort auf @YuriyNakonechnyy ... wenn Sie Java 9 oder höher verwenden, können Sie anrufen HttpURLConnection.setAuthenticator(). Leider ist die Authenticator-Instanz unter Java 8 und früheren Versionen eine JVM-weite globale Variable. Siehe: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett

133

Es gibt eine native und weniger aufdringliche Alternative, die nur für Ihren Anruf funktioniert.

URL url = new URL(“location address”);
URLConnection uc = url.openConnection();
String userpass = username + ":" + password;
String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes()));
uc.setRequestProperty ("Authorization", basicAuth);
InputStream in = uc.getInputStream();

5
Die Base64-Klasse kann vom Apache Commons Codec bereitgestellt werden.
Matthew Buckett

Hat bei mir nicht so funktioniert ... Nur so, dass @James Van Huis gut war
Miguel Ribeiro

Es ist auf Grails und vielen anderen Java-Frameworks "nativ", da alle Apache Commons Libs verwenden.
Wanderson Santos

1
Funktioniert im Allgemeinen nur, wenn Sie .trim()das Ergebnis erhalten oder eine Methodenvariante aufrufen, die keine Blockausgabe erzeugt. javax.xml.bind.DatatypeConverterscheint sicherer.
Jesse Glick

Ich habe Ihren Code in dieser Antwort zitiert. Danke
Notizen-jj

77

Sie können auch Folgendes verwenden, für das keine externen Pakete erforderlich sind:

URL url = new URL(“location address”);
URLConnection uc = url.openConnection();

String userpass = username + ":" + password;
String basicAuth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(userpass.getBytes());

uc.setRequestProperty ("Authorization", basicAuth);
InputStream in = uc.getInputStream();

10
Ich habe so lange nach einem Base64-Encoder in Java-Standardpaketen gesucht! Vielen Dank
qwertzguy

Beachten Sie, dass Sie dies für Java9 + wahrscheinlich tun müssen, --add-modules javax.xml.bindda das Paket aus dem Standardklassenpfad entfernt wurde. Und in Java11 + ist es vollständig entfernt, Sie benötigen wieder eine externe Abhängigkeit. Das ist Fortschritt!
Ed Randall

1
@ EdRandall gibt es ein java.util.Base64jetzt, so ist es in der Tat Fortschritt :)
Steven Schlansker

42

Wenn Sie die normale Anmeldung verwenden, während Sie den Benutzernamen und das Kennwort zwischen dem Protokoll und der Domäne eingeben, ist dies einfacher. Es funktioniert auch mit und ohne Login.

Beispiel-URL: http: // user: pass@domain.com/url

URL url = new URL("http://user:pass@domain.com/url");
URLConnection urlConnection = url.openConnection();

if (url.getUserInfo() != null) {
    String basicAuth = "Basic " + new String(new Base64().encode(url.getUserInfo().getBytes()));
    urlConnection.setRequestProperty("Authorization", basicAuth);
}

InputStream inputStream = urlConnection.getInputStream();

Bitte beachten Sie im Kommentar von valerybodak unten, wie es in einer Android-Entwicklungsumgebung gemacht wird.


1
Das war genau das, was ich in den letzten 30 Minuten gesucht. Vielen Dank!
Geert Schuring

Wenn Ihr Benutzername / Passwort Sonderzeichen enthält, müssten Sie diese meiner Meinung nach mit einem Urlencode versehen. Dann würden Sie im url.getUserInfo()obigen Codeausschnitt URLDecoder.decode()zuerst durchgehen (@Peter Rader).
m01

Danke, aber für Android sollten Sie Base64 wie folgt verwenden: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Authorization", basicAuth);
Valerybodak

Vielen Dank Valerybodak für diese Ergänzung!
Javabeangrinder

8

Da ich hierher gekommen bin, um eine Android-Java-Antwort zu suchen, werde ich eine kurze Zusammenfassung machen:

  1. Verwenden Sie java.net.Authenticator, wie von James van Huis gezeigt
  2. Verwenden Sie den Apache Commons HTTP-Client wie in dieser Antwort
  3. Verwenden Sie die grundlegende java.net.URLConnection und setzen Sie den Authentifizierungs-Header manuell wie hier gezeigt

Wenn Sie java.net.URLConnection mit Standardauthentifizierung in Android verwenden möchten, versuchen Sie diesen Code:

URL url = new URL("http://www.mywebsite.com/resource");
URLConnection urlConnection = url.openConnection();
String header = "Basic " + new String(android.util.Base64.encode("user:pass".getBytes(), android.util.Base64.NO_WRAP));
urlConnection.addRequestProperty("Authorization", header);
// go on setting more request headers, reading the response, etc

1
Vielen Dank. War auf der Suche nach einer Android-spezifischen Antwort!
Stephen McCormick

5

Konnte die Authentifizierung über die HttpsURLConnection einstellen

           URL myUrl = new URL(httpsURL);
            HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection();
            String userpass = username + ":" + password;
            String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes()));
            //httpsurlconnection
            conn.setRequestProperty("Authorization", basicAuth);

Einige der Änderungen wurden aus diesem Beitrag abgerufen. und Base64 stammt aus dem Paket java.util.


3

Seien Sie sehr vorsichtig mit dem Ansatz "Base64 (). Encode ()". Mein Team und ich haben 400 Probleme mit fehlerhaften Apache-Anforderungen, da am Ende der generierten Zeichenfolge ein \ r \ n hinzugefügt wird.

Wir fanden es dank Wireshark, Pakete zu schnüffeln.

Hier ist unsere Lösung:

import org.apache.commons.codec.binary.Base64;

HttpGet getRequest = new HttpGet(endpoint);
getRequest.addHeader("Authorization", "Basic " + getBasicAuthenticationEncoding());

private String getBasicAuthenticationEncoding() {

        String userPassword = username + ":" + password;
        return new String(Base64.encodeBase64(userPassword.getBytes()));
    }

Ich hoffe es hilft!


3

Verwenden Sie diesen Code für die Basisauthentifizierung.

URL url = new URL(path);
String userPass = "username:password";
String basicAuth = "Basic " + Base64.encodeToString(userPass.getBytes(), Base64.DEFAULT);//or
//String basicAuth = "Basic " + new String(Base64.encode(userPass.getBytes(), Base64.No_WRAP));
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty("Authorization", basicAuth);
urlConnection.connect();


2

Ich möchte eine Antwort für den Fall geben, dass Sie keine Kontrolle über den Code haben, der die Verbindung öffnet. Wie ich es getan habe, als ich URLClassLoadereine JAR-Datei von einem passwortgeschützten Server geladen habe.

Die AuthenticatorLösung würde funktionieren, hat jedoch den Nachteil, dass zuerst versucht wird, den Server ohne Kennwort zu erreichen, und erst, nachdem der Server nach einem Kennwort gefragt hat, eines bereitgestellt wird. Dies ist eine unnötige Rundreise, wenn Sie bereits wissen, dass der Server ein Kennwort benötigt.

public class MyStreamHandlerFactory implements URLStreamHandlerFactory {

    private final ServerInfo serverInfo;

    public MyStreamHandlerFactory(ServerInfo serverInfo) {
        this.serverInfo = serverInfo;
    }

    @Override
    public URLStreamHandler createURLStreamHandler(String protocol) {
        switch (protocol) {
            case "my":
                return new MyStreamHandler(serverInfo);
            default:
                return null;
        }
    }

}

public class MyStreamHandler extends URLStreamHandler {

    private final String encodedCredentials;

    public MyStreamHandler(ServerInfo serverInfo) {
        String strCredentials = serverInfo.getUsername() + ":" + serverInfo.getPassword();
        this.encodedCredentials = Base64.getEncoder().encodeToString(strCredentials.getBytes());
    }

    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        String authority = url.getAuthority();
        String protocol = "http";
        URL directUrl = new URL(protocol, url.getHost(), url.getPort(), url.getFile());

        HttpURLConnection connection = (HttpURLConnection) directUrl.openConnection();
        connection.setRequestProperty("Authorization", "Basic " + encodedCredentials);

        return connection;
    }

}

Dadurch wird ein neues Protokoll registriert, mydas httpbeim Hinzufügen von Anmeldeinformationen ersetzt wird. So bei der Erstellung der neuen URLClassLoaderersetzen Sie einfach httpmit myund alles ist in Ordnung. Ich weiß, URLClassLoaderdass ein Konstruktor bereitgestellt wird, der eine verwendet, URLStreamHandlerFactoryaber diese Factory wird nicht verwendet, wenn die URL auf eine JAR-Datei verweist.


1

Seit Java 9 können Sie dies tun

URL url = new URL("http://www.example.com");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setAuthenticator(new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication ("USER", "PASS".toCharArray());
    }
});

2
Ich habe die setAuthenticator()Methode nicht gesehen .
WesternGun

0

ANDROD-UMSETZUNG Eine vollständige Methode zum Anfordern einer Daten- / Zeichenfolgenantwort vom Webdienst, der eine Autorisierung mit Benutzername und Kennwort anfordert

public static String getData(String uri, String userName, String userPassword) {
        BufferedReader reader = null;
        byte[] loginBytes = (userName + ":" + userPassword).getBytes();

        StringBuilder loginBuilder = new StringBuilder()
                .append("Basic ")
                .append(Base64.encodeToString(loginBytes, Base64.DEFAULT));

        try {
            URL url = new URL(uri);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.addRequestProperty("Authorization", loginBuilder.toString());

            StringBuilder sb = new StringBuilder();
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = reader.readLine())!= null){
                sb.append(line);
                sb.append("\n");
            }

            return  sb.toString();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (null != reader){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

0

Ich habe das so gemacht, dass du es tun musst, einfach kopieren, einfügen, glücklich sein

    HttpURLConnection urlConnection;
    String url;
 //   String data = json;
    String result = null;
    try {
        String username ="danish.hussain@gmail.com";
        String password = "12345678";

        String auth =new String(username + ":" + password);
        byte[] data1 = auth.getBytes(UTF_8);
        String base64 = Base64.encodeToString(data1, Base64.NO_WRAP);
        //Connect
        urlConnection = (HttpURLConnection) ((new URL(urlBasePath).openConnection()));
        urlConnection.setDoOutput(true);
        urlConnection.setRequestProperty("Content-Type", "application/json");
        urlConnection.setRequestProperty("Authorization", "Basic "+base64);
        urlConnection.setRequestProperty("Accept", "application/json");
        urlConnection.setRequestMethod("POST");
        urlConnection.setConnectTimeout(10000);
        urlConnection.connect();
        JSONObject obj = new JSONObject();

        obj.put("MobileNumber", "+97333746934");
        obj.put("EmailAddress", "danish.hussain@mee.com");
        obj.put("FirstName", "Danish");
        obj.put("LastName", "Hussain");
        obj.put("Country", "BH");
        obj.put("Language", "EN");
        String data = obj.toString();
        //Write
        OutputStream outputStream = urlConnection.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
        writer.write(data);
        writer.close();
        outputStream.close();
        int responseCode=urlConnection.getResponseCode();
        if (responseCode == HttpsURLConnection.HTTP_OK) {
            //Read
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));

        String line = null;
        StringBuilder sb = new StringBuilder();

        while ((line = bufferedReader.readLine()) != null) {
            sb.append(line);
        }

        bufferedReader.close();
        result = sb.toString();

        }else {
        //    return new String("false : "+responseCode);
        new String("false : "+responseCode);
        }

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.