Conectando a URL Remota que Requer Autenticação Usando Java

125

Como faço para conectar-me a uma URL remota em Java que requer autenticação. Estou tentando encontrar uma maneira de modificar o código a seguir para poder fornecer programaticamente um nome de usuário / senha para que ele não ative um 401.

URL url = new URL(String.format("http://%s/manager/list", _host + ":8080"));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
user14128
fonte
Verifique aqui: stackoverflow.com/questions/1359689/…
WesternGun 14/03/19

Respostas:

134

Você pode definir o autenticador padrão para solicitações http como esta:

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

Além disso, se você precisar de mais flexibilidade, consulte o Apache HttpClient , que oferece mais opções de autenticação (além de suporte à sessão, etc.)

James Van Huis
fonte
4
Como você lida com um evento de autenticação incorreto? [Por exemplo, se o usuário fornecer credenciais de autenticação de nome de usuário e senha que não correspondam a nada]?
SK9
2
O código acima funciona, mas é bastante implícito quanto ao que está acontecendo. Há subclassificação e substituição de método acontecendo lá, procure nos documentos dessas classes se você quiser saber o que está acontecendo. O código aqui é mais explícitas javacodegeeks
Fuchida
12
É possível definir específico Authenticatorpor URL.openConnection()chamada específica em vez de defini-la globalmente?
Yuriy Nakonechnyy
@Yura: não. Tem que ser global. No entanto, você pode fazer coisas erradas, como definir um autenticador global que retire as credenciais de variáveis ​​locais do encadeamento e defina as credenciais por encadeamento antes de fazer a conexão HTTP.
David Given
4
Em resposta a @YuriyNakonechnyy ... se você estiver usando o Java 9 ou superior, poderá ligar HttpURLConnection.setAuthenticator(). Infelizmente no Java 8 e versões anteriores, a instância do Authenticator é uma variável global da JVM. Veja: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett
133

Existe uma alternativa nativa e menos invasiva, que funciona apenas para sua ligação.

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
fonte
5
A classe Base64 pode ser fornecida pelo Apache Commons Codec.
Matthew Buckett
Não funcionou para mim dessa maneira ... Apenas da maneira que @James Van Huis era bom #
Miguel Ribeiro
É 'nativo' no Grails e em muitos outros frameworks Java, porque todos eles usam o Apache Commons Libs.
Wanderson Santos
1
Não funciona em geral, a menos que você obtenha .trim()o resultado ou chame uma variante de método que não produza saída em pedaços. javax.xml.bind.DatatypeConverterparece mais seguro.
Jesse Glick
Eu citei seu código nesta resposta Obrigado
notes-jj
77

Você também pode usar o seguinte, que não requer o uso de pacotes 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
fonte
10
Eu estive procurando por um codificador Base64 dentro de pacotes padrão java por tanto tempo! Obrigado
qwertzguy
Observe que, para o Java9 +, você provavelmente precisará --add-modules javax.xml.bindremover o pacote do caminho de classe padrão. E no Java11 + ele é completamente removido, você precisa de uma dependência externa novamente. Tal é o progresso!
Ed Randall
1
@EdRandall há um java.util.Base64agora por isso é progredir na verdade :)
Steven Schlansker
42

Se você estiver usando o login normal enquanto digita o nome de usuário e a senha entre o protocolo e o domínio, isso é mais simples. Também funciona com e sem login.

URL de amostra: http: // usuário: [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();

Observe no comentário, da valerybodak, abaixo como isso é feito em um ambiente de desenvolvimento Android.

javabeangrinder
fonte
1
Era exatamente isso que eu procurava nos últimos 30 minutos. Muito obrigado!
Geert Schuring
Se seu nome de usuário / senha contiver caracteres especiais, acredito que você precisaria codificá-los. Em seguida, no trecho de código acima, você deve passar url.getUserInfo()para obtener URLDecoder.decode()primeiro (@ Peter Rader).
M01
Obrigado, mas para o Android você deve usar o Base64 da seguinte maneira: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Authorization", basicAuth);
valerybodak
Obrigado valerybodak por esse complemento!
javabeangrinder
8

Como eu vim aqui à procura de uma resposta Java para Android, vou fazer um breve resumo:

  1. Use java.net.Authenticator como mostrado por James van Huis
  2. Use o Cliente HTTP Apache Commons , como em nesta resposta
  3. Use java.net.URLConnection básico e defina o cabeçalho de autenticação manualmente, como mostrado aqui

Se você deseja usar o java.net.URLConnection com autenticação básica no Android, tente 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
fonte
1
Obrigado. Estava procurando uma resposta específica para Android!
Stephen McCormick
5

Conseguiu definir a autenticação usando o 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);

algumas das alterações obtidas nesta postagem. e Base64 é do pacote java.util.

Tim
fonte
3

Tenha muito cuidado com a abordagem "Base64 (). Encode ()", minha equipe e eu recebemos 400 problemas de solicitações ruins do Apache porque adiciona um \ r \ n no final da string gerada.

Achamos que ele cheirava pacotes graças ao Wireshark.

Aqui está a nossa solução:

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 que ajude!

lboix
fonte
3

Use este código para autenticação 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
fonte
2

Gostaria de fornecer uma resposta para o caso de você não ter controle sobre o código que abre a conexão. Como eu fiz ao usar oURLClassLoader para carregar um arquivo jar de um servidor protegido por senha.

A Authenticatorsolução funcionaria, mas tem a desvantagem de tentar primeiro acessar o servidor sem uma senha e somente depois que o servidor solicitar uma senha forneça uma. Essa é uma ida e volta desnecessária se você já sabe que o servidor precisaria de uma senha.

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

}

Isso registra um novo protocolo myque é substituído por httpquando as credenciais são adicionadas. Portanto, ao criar o novo, URLClassLoaderbasta substituir httppor mye está tudo bem. Eu sei que URLClassLoaderfornece um construtor que leva um, URLStreamHandlerFactorymas esta fábrica não é usada se o URL aponta para um arquivo jar.

FLUXparticle
fonte
1

Desde o Java 9, você pode fazer isso

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
fonte
2
Não vi setAuthenticator()método.
WesternGun 14/03/19
0

IMPLEMENTAÇÃO ANDROD Um método completo para solicitar resposta de dados / string do serviço da Web solicitando autorização com nome de usuário e senha

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

eu fiz isso dessa maneira, você precisa fazer isso basta copiar e colar, seja 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
fonte