Conexión a una URL remota que requiere autenticación con Java

125

¿Cómo me conecto a una URL remota en Java que requiere autenticación? Estoy tratando de encontrar una manera de modificar el siguiente código para poder proporcionar programáticamente un nombre de usuario / contraseña para que no arroje un 401.

URL url = new URL(String.format("http://%s/manager/list", _host + ":8080"));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
usuario14128
fuente
Consulte aquí: stackoverflow.com/questions/1359689/…
WesternGun

Respuestas:

134

Puede configurar el autenticador predeterminado para solicitudes http como este:

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

Además, si necesita más flexibilidad, puede consultar el HttpClient de Apache , que le dará más opciones de autenticación (así como soporte de sesión, etc.)

James Van Huis
fuente
44
¿Cómo manejas un evento de autenticación malo? [Por ejemplo, si el usuario proporciona credenciales de autenticación de nombre de usuario y contraseña que no coinciden con nada]?
SK9
2
El código anterior funciona pero está bastante implícito en cuanto a lo que está sucediendo. Hay subclases y anulación de métodos allí, profundice en los documentos de esas clases si le importa saber qué está pasando. El código aquí es más explícito javacodegeeks
Fuchida
12
¿Es posible establecer Authenticatoruna URL.openConnection()invocación específica por específica en lugar de establecerla globalmente?
Yuriy Nakonechnyy
@Yura: no. Tiene que ser global. Sin embargo, puede hacer cosas malas, como configurar un autenticador global que extraiga las credenciales de las variables locales de subproceso y establecer las credenciales por subproceso antes de realizar la conexión HTTP.
David dado
44
En respuesta a @YuriyNakonechnyy ... si está utilizando Java 9 o superior, puede llamar HttpURLConnection.setAuthenticator(). Desafortunadamente en Java 8 y versiones anteriores, la instancia de Authenticator es una variable global de JVM. Ver: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett
133

Hay una alternativa nativa y menos intrusiva, que funciona solo para su llamada.

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
fuente
55
La clase Base64 puede ser proporcionada por Apache Commons Codec.
Matthew Buckett
No funcionó para mí de esta manera ... Solo la forma en que @James Van Huis fue bueno
Miguel Ribeiro
Es 'nativo' en Grails y muchos otros frameworks de Java porque todos usan Apache Commons Libs.
Wanderson Santos
1
No funciona en general a menos que .trim()el resultado, o llame a una variante de método que no produce una salida fragmentada. javax.xml.bind.DatatypeConverterParece más seguro
Jesse Glick
Cité su código en esta respuesta Gracias
notes-jj
77

También puede usar lo siguiente, que no requiere el uso de paquetes externos:

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
fuente
10
¡He estado buscando un codificador Base64 dentro de los paquetes estándar de Java durante tanto tiempo! Gracias
qwertzguy
Tenga en cuenta que para Java9 + probablemente tendrá que hacerlo --add-modules javax.xml.bindya que eliminaron el paquete de la ruta de clase predeterminada. Y en Java11 + se elimina por completo, necesita una dependencia externa nuevamente. ¡Tal es el progreso!
Ed Randall
1
@EdRandall hay un java.util.Base64ahora, así que es un verdadero progreso :)
Steven Schlansker
42

Si está utilizando el inicio de sesión normal mientras ingresa el nombre de usuario y la contraseña entre el protocolo y el dominio, esto es más simple. También funciona con y sin inicio de sesión.

Ejemplo de URL: http: // usuario: [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();

Tenga en cuenta en el comentario, de valerybodak, a continuación cómo se hace en un entorno de desarrollo de Android.

javabeangrinder
fuente
1
Esto fue exactamente lo que he estado buscando durante los últimos 30 minutos. ¡Muchas gracias!
Geert Schuring
Si su nombre de usuario / contraseña contiene caracteres especiales, creo que necesitaría codificarlos. Luego, en el fragmento de código anterior, url.getUserInfo()pasarías URLDecoder.decode()primero (@Peter Rader).
m01
Gracias, pero para Android debe usar Base64 de la siguiente manera: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Autorización", basicAuth);
Valerybodak
Gracias valerybodak por ese complemento!
javabeangrinder
8

Como vine aquí buscando un Android-Java-Answer voy a hacer un breve resumen:

  1. Use java.net.Authenticator como lo muestra James van Huis
  2. Utilice el cliente HTTP Apache Commons , como en esta respuesta
  3. Use java.net.URLConnection básico y configure el encabezado de autenticación manualmente como se muestra aquí

Si desea utilizar java.net.URLConnection con autenticación básica en Android, pruebe este código:

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
fuente
1
Gracias. ¡Estaba buscando una respuesta específica de Android!
Stephen McCormick
5

Pude configurar la autenticación usando 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);

Algunos de los cambios obtenidos de esta publicación. y Base64 es del paquete java.util.

Tim
fuente
3

Tenga mucho cuidado con el enfoque "Base64 (). Encode ()", mi equipo y yo recibimos 400 problemas de solicitud incorrecta de Apache porque agrega un \ r \ n al final de la cadena generada.

Lo encontramos oliendo paquetes gracias a Wireshark.

Aquí está nuestra solución:

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

¡Espero eso ayude!

lboix
fuente
3

Use este código para la autenticación básica.

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
fuente
2

Me gustaría proporcionar una respuesta para el caso de que no tenga control sobre el código que abre la conexión. Como lo hice al usar el URLClassLoaderpara cargar un archivo jar desde un servidor protegido con contraseña.

La Authenticatorsolución funcionaría, pero tiene el inconveniente de que primero intenta llegar al servidor sin una contraseña y solo después de que el servidor solicite una contraseña. Es un viaje de ida y vuelta innecesario si ya sabe que el servidor necesitaría una contraseña.

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

}

Esto registra un nuevo protocolo myque se reemplaza httpcuando se agregan las credenciales. Entonces, al crear el nuevo URLClassLoadersolo reemplace httpcon myy todo está bien. Sé que URLClassLoaderproporciona un constructor que toma un URLStreamHandlerFactorypero esta fábrica no se usa si la URL apunta a un archivo jar.

Partícula FLUX
fuente
1

Desde Java 9, puedes hacer esto

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
fuente
2
No he visto el setAuthenticator()método.
WesternGun
0

IMPLEMENTACIÓN DE ANDROD Un método completo para solicitar una respuesta de datos / cadena del servicio web solicitando autorización con nombre de usuario y contraseña

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
fuente
0

Lo hice de esta manera, necesitas hacer esto, solo copia y pega, sé feliz

    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 Danish Haider
fuente