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

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


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

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

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

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


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

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.


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!


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


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.


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

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

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 ="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();
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.