Connessione a un URL remoto che richiede l'autenticazione tramite Java


125

Come mi connetto a un URL remoto in Java che richiede l'autenticazione. Sto cercando di trovare un modo per modificare il seguente codice per poter fornire programmaticamente un nome utente / password in modo che non generi un 401.

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

Risposte:


134

Puoi impostare l'autenticatore predefinito per le richieste http come questa:

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

Inoltre, se hai bisogno di maggiore flessibilità, puoi controllare Apache HttpClient , che ti darà più opzioni di autenticazione (così come il supporto della sessione, ecc.)


4
Come gestisci un evento di autenticazione errato? [Ad esempio, se l'utente fornisce credenziali di autenticazione nome utente e password che non corrispondono a nulla]?
SK9

2
Il codice sopra funziona ma è abbastanza implicito su cosa sta succedendo. Ci sono sottoclassi e sovrascritture di metodi in corso, approfondisci i documenti per quelle classi se ti interessa sapere cosa sta succedendo. Il codice qui è javacodegeeks
Fuchida

12
È possibile impostare specifici Authenticatorper URL.openConnection()invocazione specifica piuttosto che impostarli a livello globale?
Yuriy Nakonechnyy

@ Yura: no. Deve essere globale. Puoi, tuttavia, fare cose malvagie come impostare un autenticatore globale che estrae le credenziali dalle variabili locali del thread e impostare le credenziali per thread prima di effettuare la connessione HTTP.
David dato

4
In risposta a @YuriyNakonechnyy ... se stai usando Java 9 o versioni successive, puoi chiamare HttpURLConnection.setAuthenticator(). Sfortunatamente su Java 8 e versioni precedenti, l'istanza di Authenticator è una variabile globale a livello di JVM. Vedi: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett

133

C'è un'alternativa nativa e meno invadente, che funziona solo per la tua chiamata.

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
La classe Base64 può essere fornita da Apache Commons Codec.
Matthew Buckett

Non ha funzionato per me in questo modo ... Solo il modo in cui @James Van Huis era buono
Miguel Ribeiro

È "nativo" su Grails e molti altri framework Java perché tutti usano Apache Commons Libs.
Wanderson Santos

1
Non funziona in generale a meno che non venga visualizzato .trim()il risultato o si chiami una variante del metodo che non produce output in blocchi. javax.xml.bind.DatatypeConvertersembra più sicuro.
Jesse Glick

Ho citato il tuo codice in questa risposta Grazie
note-jj

77

È inoltre possibile utilizzare quanto segue, che non richiede l'utilizzo di pacchetti esterni:

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
Ho cercato un codificatore Base64 all'interno di pacchetti standard Java per così tanto tempo! Grazie
qwertzguy

Nota che per Java9 + probabilmente dovrai farlo --add-modules javax.xml.bindpoiché hanno rimosso il pacchetto dal classpath predefinito. E in Java11 + viene rimosso del tutto, è necessaria di nuovo una dipendenza esterna. Questo è il progresso!
Ed Randall

1
@EdRandall c'è un java.util.Base64adesso quindi è davvero un progresso :)
Steven Schlansker

42

Se stai usando il login normale mentre inserisci il nome utente e la password tra il protocollo e il dominio, questo è più semplice. Funziona anche con e senza login.

URL di esempio: 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();

Si prega di notare nel commento, da valerybodak, di seguito come è fatto in un ambiente di sviluppo Android.


1
Questo era esattamente quello che stavo cercando negli ultimi 30 minuti. Molte grazie!
Geert Schuring

Se il tuo nome utente / password contengono caratteri speciali, credo che dovresti codificarli nell'URL. Poi, nel frammento di codice di cui sopra, si dovrebbe passare url.getUserInfo()traverso la URLDecoder.decode()prima (@Peter Rader).
m01

Grazie, ma per Android dovresti usare Base64 come segue: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Autorizzazione", basicAuth);
valerybodak

Grazie valerybodak per quel complemento!
javabeangrinder

8

Dato che sono venuto qui alla ricerca di una risposta Android-Java, farò un breve riassunto:

  1. Usa java.net.Authenticator come mostrato da James van Huis
  2. Usa il client HTTP Apache Commons , come in questa risposta
  3. Utilizzare java.net.URLConnection di base e impostare manualmente l'intestazione di autenticazione come mostrato qui

Se vuoi usare java.net.URLConnection con l'autenticazione di base in Android prova questo codice:

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
Grazie. Stavo cercando una risposta specifica per Android!
Stephen McCormick,

5

È stato in grado di impostare l'autenticazione utilizzando HttpsURLConnection

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

alcune delle modifiche recuperate da questo post. e Base64 proviene dal pacchetto java.util.


3

Fai molta attenzione con l'approccio "Base64 (). Encode ()", io e il mio team abbiamo riscontrato 400 problemi di richieste errate di Apache perché aggiunge un \ r \ n alla fine della stringa generata.

L'abbiamo trovato sniffando pacchetti grazie a Wireshark.

Ecco la nostra soluzione:

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

Spero che sia d'aiuto!


3

Usa questo codice per l'autenticazione di base.

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

Vorrei fornire una risposta per il caso in cui non hai il controllo sul codice che apre la connessione. Come ho fatto quando ho usato URLClassLoaderper caricare un file jar da un server protetto da password.

La Authenticatorsoluzione funzionerebbe ma ha l'inconveniente di tentare prima di raggiungere il server senza una password e solo dopo che il server ne ha chiesto una. Questo è un viaggio di andata e ritorno non necessario se sai già che il server avrebbe bisogno di una password.

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;
    }

}

Questo registra un nuovo protocollo myche viene sostituito da httpquando vengono aggiunte le credenziali. Quindi, quando crei il nuovo, URLClassLoadersostituiscilo httpcon mye tutto va bene. So che URLClassLoaderfornisce un costruttore che accetta un URLStreamHandlerFactoryma questa factory non viene utilizzata se l'URL punta a un file jar.


1

A partire da Java 9, puoi farlo

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
Non ho visto il setAuthenticator()metodo.
WesternGun

0

IMPLEMENTAZIONE ANDROD Un metodo completo per richiedere la risposta di dati / stringhe dal servizio web che richiede l'autorizzazione con nome utente e password

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

l'ho fatto in questo modo, devi solo copiare e incollare, sii felice

    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();
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.