Connexion à une URL distante nécessitant une authentification à l'aide de Java

125

Comment puis-je me connecter à une URL distante en Java qui nécessite une authentification. J'essaie de trouver un moyen de modifier le code suivant pour pouvoir fournir par programme un nom d'utilisateur / mot de passe afin qu'il ne lance pas un 401.

URL url = new URL(String.format("http://%s/manager/list", _host + ":8080"));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
user14128
la source
Vérifiez ici: stackoverflow.com/questions/1359689/…
WesternGun

Réponses:

134

Vous pouvez définir l'authentificateur par défaut pour les requêtes http comme ceci:

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

De plus, si vous avez besoin de plus de flexibilité, vous pouvez consulter Apache HttpClient , qui vous donnera plus d'options d'authentification (ainsi que la prise en charge de session, etc.)

James Van Huis
la source
4
Comment gérez-vous un mauvais événement d'authentification? [Par exemple, si l'utilisateur fournit des informations d'authentification par nom d'utilisateur et mot de passe qui ne correspondent à rien]?
SK9
2
Le code ci-dessus fonctionne mais est assez implicite quant à ce qui se passe. Il y a des sous-classes et des remplacements de méthodes là-bas, fouillez dans la documentation de ces classes si vous voulez savoir ce qui se passe. Le code ici est plus explicite javacodegeeks
Fuchida
12
Est-il possible de définir spécifique Authenticatorpar URL.openConnection()appel spécifique plutôt que de le définir globalement?
Yuriy Nakonechnyy
@Yura: non. Cela doit être mondial. Vous pouvez, cependant, faire des choses maléfiques telles que la définition d'un authentificateur global qui extrait les informations d'identification des variables locales de thread, et définir les informations d'identification par thread avant d'établir la connexion HTTP.
David donné
4
En réponse à @YuriyNakonechnyy ... si vous utilisez Java 9 ou supérieur, vous pouvez appeler HttpURLConnection.setAuthenticator(). Malheureusement sur Java 8 et les versions antérieures, l'instance Authenticator est une variable globale à l'échelle de la JVM. Voir: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett
134

Il existe une alternative native et moins intrusive, qui ne fonctionne que pour votre appel.

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();
Wanderson Santos
la source
5
La classe Base64 peut être fournie par Apache Commons Codec.
Matthew Buckett
Cela n'a pas fonctionné pour moi de cette façon ... Seulement la façon dont @James Van Huis était bon
Miguel Ribeiro
Il est «natif» sur Grails et de nombreux autres frameworks Java car ils utilisent tous Apache Commons Libs.
Wanderson Santos
1
Ne fonctionne pas en général sauf si vous obtenez .trim()le résultat ou appelez une variante de méthode qui ne produit pas de sortie fragmentée. javax.xml.bind.DatatypeConvertersemble plus sûr.
Jesse Glick
J'ai cité votre code dans cette réponse Merci
notes-jj
77

Vous pouvez également utiliser les éléments suivants, qui ne nécessitent pas l'utilisation de packages externes:

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();
gloo
la source
10
Je cherchais depuis si longtemps un encodeur Base64 dans les packages standard java! Merci
qwertzguy
Notez que pour Java9 +, vous devrez probablement le faire --add-modules javax.xml.bindcar ils ont supprimé le package du chemin de classe par défaut. Et dans Java11 +, il est complètement supprimé, vous avez à nouveau besoin d'une dépendance externe. Tel est le progrès!
Ed Randall
1
@EdRandall il y a un java.util.Base64moment, donc c'est un progrès :)
Steven Schlansker
42

Si vous utilisez la connexion normale lors de la saisie du nom d'utilisateur et du mot de passe entre le protocole et le domaine, c'est plus simple. Cela fonctionne également avec et sans connexion.

Exemple d'URL: http: // utilisateur: [email protected]/url

URL url = new URL("http://user:[email protected]/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();

Veuillez noter dans le commentaire, de valerybodak, ci-dessous comment cela se fait dans un environnement de développement Android.

javabeangrinder
la source
1
C'est exactement ce que je cherchais depuis 30 minutes. Merci beaucoup!
Geert Schuring
Si votre nom d'utilisateur / mot de passe contient des caractères spéciaux, je pense que vous devrez les encoder en url. Ensuite, dans l'extrait de code ci-dessus, vous url.getUserInfo()passeriez d' URLDecoder.decode()abord par (@Peter Rader).
m01
Merci, mais pour Android, vous devez utiliser Base64 comme suit: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Autorisation", basicAuth);
valerybodak
Merci valerybodak pour ce complément!
javabeangrinder
8

Comme je suis venu ici à la recherche d'une réponse Android-Java-Answer, je vais faire un bref résumé:

  1. Utilisez java.net.Authenticator comme indiqué par James van Huis
  2. Utilisez le client HTTP Apache Commons , comme dans cette réponse
  3. Utilisez java.net.URLConnection de base et définissez manuellement l'en-tête d'authentification comme indiqué ici

Si vous souhaitez utiliser java.net.URLConnection avec l'authentification de base sous Android, essayez ce 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
DaniEll
la source
1
Merci. Je cherchais une réponse spécifique à Android!
Stephen McCormick
5

Était capable de définir l'authentification à l'aide de la 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);

quelques-uns des changements extraits de ce post. et Base64 provient du package java.util.

Tim
la source
3

Soyez vraiment prudent avec l'approche "Base64 (). Encode ()", mon équipe et moi avons eu 400 problèmes de requête Apache car elle ajoute un \ r \ n à la fin de la chaîne générée.

Nous l'avons trouvé reniflant des paquets grâce à Wireshark.

Voici notre solution:

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

J'espère que ça aide!

lboix
la source
3

Utilisez ce code pour l'authentification de 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();

Sarith Nob
la source
2

Je voudrais fournir une réponse pour le cas où vous n'avez pas de contrôle sur le code qui ouvre la connexion. Comme je l'ai fait lors de l'utilisation de URLClassLoaderpour charger un fichier jar à partir d'un serveur protégé par mot de passe.

La Authenticatorsolution fonctionnerait mais présente l'inconvénient qu'elle essaie d'abord d'atteindre le serveur sans mot de passe et seulement après que le serveur demande un mot de passe en fournit un. C'est un aller-retour inutile si vous savez déjà que le serveur aurait besoin d'un mot de passe.

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

}

Cela enregistre un nouveau protocole myqui est remplacé par httplorsque les informations d'identification sont ajoutées. Donc, lors de la création du nouveau, URLClassLoaderremplacez-le httppar myet tout va bien. Je sais que URLClassLoaderfournit un constructeur qui prend un URLStreamHandlerFactorymais cette usine n'est pas utilisée si l'URL pointe vers un fichier jar.

FLUXparticule
la source
1

Depuis Java 9, vous pouvez le faire

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());
    }
});
Punyapat
la source
2
Je n'ai pas vu de setAuthenticator()méthode.
WesternGun
0

MISE EN ŒUVRE D'ANDROD Une méthode complète pour demander une réponse de données / chaîne au service Web demandant une autorisation avec un nom d'utilisateur et un mot de passe

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();
                }
            }
        }
    }
Emmanuel Mtali
la source
0

je l'ai fait de cette façon, vous devez le faire, il suffit de copier-coller, soyez heureux

    HttpURLConnection urlConnection;
    String url;
 //   String data = json;
    String result = null;
    try {
        String username ="[email protected]";
        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", "[email protected]");
        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();
    }
Syed Danois Haider
la source