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.