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

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


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

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

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

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


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

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.


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!


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


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.


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

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

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 ="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();
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.