Łączenie się ze zdalnym adresem URL, które wymaga uwierzytelnienia za pomocą języka Java


125

Jak połączyć się ze zdalnym adresem URL w Javie, który wymaga uwierzytelnienia. Próbuję znaleźć sposób na zmodyfikowanie następującego kodu, aby móc programowo podać nazwę użytkownika / hasło, aby nie zgłaszał błędu 401.

URL url = new URL(String.format("http://%s/manager/list", _host + ":8080"));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();

Odpowiedzi:


134

Możesz ustawić domyślny program uwierzytelniający dla żądań http w następujący sposób:

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

Ponadto, jeśli potrzebujesz większej elastyczności, możesz sprawdzić Apache HttpClient , który zapewnia więcej opcji uwierzytelniania (a także obsługę sesji itp.)


4
Jak sobie radzisz ze zdarzeniem złego uwierzytelnienia? [Na przykład, jeśli użytkownik poda nazwę użytkownika i hasło uwierzytelniające, które do niczego nie pasują]?
SK9

2
Powyższy kod działa, ale jest dość niejawny, co się dzieje. Działają tam podklasy i zastępowanie metod, zagłęb się w dokumentację tych klas, jeśli chcesz wiedzieć, co się dzieje. Kod tutaj jest bardziej wyraźny javacodegeeks
Fuchida

12
Czy można ustawić określone Authenticatordla konkretnego URL.openConnection()wywołania zamiast ustawiać je globalnie?
Yuriy Nakonechnyy

@Yura: nie. To musi być globalne. Możesz jednak robić złe rzeczy, takie jak ustawienie globalnego uwierzytelniacza, który wyciąga referencje ze zmiennych lokalnych wątku i ustawia poświadczenia dla wątku przed nawiązaniem połączenia HTTP.
David Given

4
W odpowiedzi na @YuriyNakonechnyy ... jeśli używasz Java 9 lub nowszej, możesz zadzwonić HttpURLConnection.setAuthenticator(). Niestety w Javie 8 i wcześniejszych wystąpienie Authenticator jest zmienną globalną obejmującą całą maszynę JVM. Zobacz: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett

133

Istnieje natywna i mniej inwazyjna alternatywa, która działa tylko na Twój telefon.

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
Klasa Base64 może być dostarczona przez Apache Commons Codec.
Matthew Buckett

To nie zadziałało dla mnie w ten sposób ... Tylko sposób, w jaki @James Van Huis był dobry
Miguel Ribeiro

Jest „natywny” w Grails i wielu innych frameworkach Java, ponieważ wszystkie korzystają z Apache Commons Libs.
Wanderson Santos

1
Ogólnie nie działa, chyba że uzyskasz .trim()wynik lub wywołasz wariant metody, który nie generuje fragmentów danych wyjściowych. javax.xml.bind.DatatypeConverterwydaje się bezpieczniejsze.
Jesse Glick

Zacytowałem Twój kod w tej odpowiedzi Dziękuję
notes-jj

77

Możesz także skorzystać z następujących, które nie wymagają korzystania z zewnętrznych pakietów:

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
Tak długo szukałem kodera Base64 w standardowych pakietach Java! Dziękuję
qwertzguy

Zauważ, że w przypadku Java9 + prawdopodobnie będziesz musiał to zrobić, --add-modules javax.xml.bindponieważ usunęli pakiet z domyślnej ścieżki klas. A w Java11 + jest całkowicie usunięty, potrzebujesz ponownie zewnętrznej zależności. Taki postęp!
Ed Randall

1
@EdRandall jest java.util.Base64teraz, więc to rzeczywiście postęp :)
Steven Schlansker

42

Jeśli używasz zwykłego logowania podczas wprowadzania nazwy użytkownika i hasła między protokołem a domeną, jest to prostsze. Działa również zi bez logowania.

Przykładowy adres URL: http: // użytkownik: hasło@domena.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();

Zwróć uwagę w komentarzu od valerybodak, poniżej, jak to się robi w środowisku programistycznym Androida.


1
To było dokładnie to, czego szukałem przez ostatnie 30 minut. Wielkie dzięki!
Geert Schuring

Jeśli twoja nazwa użytkownika / hasło zawiera znaki specjalne, uważam, że musisz je zakodować. Następnie, we fragmencie kodu powyżej, należy zdać url.getUserInfo()thorugh URLDecoder.decode()pierwszy (@Peter Rader).
m01

Dzięki, ale w przypadku Androida powinieneś użyć Base64 w następujący sposób: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Autoryzacja", basicAuth);
valerybodak

Dziękuję Valerybodak za to uzupełnienie!
javabeangrinder

8

Ponieważ przyszedłem tutaj w poszukiwaniu odpowiedzi na Androida-Java, zamierzam zrobić krótkie podsumowanie:

  1. Użyj java.net.Authenticator, jak pokazał James van Huis
  2. Użyj klienta HTTP Apache Commons , jak w tej odpowiedzi
  3. Użyj podstawowego java.net.URLConnection i ustaw ręcznie nagłówek uwierzytelniania, jak pokazano tutaj

Jeśli chcesz korzystać z java.net.URLConnection z podstawowym uwierzytelnianiem w systemie Android, wypróbuj ten kod:

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
Dzięki. Szukałem odpowiedzi na Androida!
Stephen McCormick

5

Był w stanie ustawić uwierzytelnianie przy użyciu 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);

kilka zmian pobranych z tego postu. a Base64 pochodzi z pakietu java.util.


3

Bądź bardzo ostrożny z podejściem "Base64 (). Encode ()", mój zespół i ja otrzymaliśmy 400 problemów z błędnymi żądaniami Apache, ponieważ dodaje \ r \ n na końcu wygenerowanego ciągu.

Okazało się, że przechwytuje pakiety dzięki Wireshark.

Oto nasze rozwiązanie:

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

Mam nadzieję, że to pomoże!


3

Użyj tego kodu do podstawowego uwierzytelnienia.

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

Chciałbym udzielić odpowiedzi w przypadku, gdy nie masz kontroli nad kodem otwierającym połączenie. Tak jak zrobiłem, gdy URLClassLoaderładowałem plik jar z serwera chronionego hasłem.

AuthenticatorRozwiązanie będzie działać, ale ma tę wadę, że najpierw próbuje połączyć się z serwerem bez hasła i dopiero po serwer prosi o hasło zapewnia jeden. To niepotrzebna podróż w obie strony, jeśli już wiesz, że serwer będzie potrzebował hasł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;
    }

}

Spowoduje to zarejestrowanie nowego protokołu, myktóry jest zastępowany httppo dodaniu poświadczeń. Więc podczas tworzenia nowego URLClassLoaderpo prostu wymienić httpsię myi wszystko jest w porządku. Wiem, że URLClassLoaderzapewnia konstruktor, który przyjmuje, URLStreamHandlerFactoryale ta fabryka nie jest używana, jeśli adres URL wskazuje na plik jar.


1

Od wersji Java 9 możesz to zrobić

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
Nie widziałem setAuthenticator()metody.
WesternGun,

0

WDROŻENIE ANDRODA Kompletna metoda żądania danych / odpowiedzi ciągu z usługi sieciowej żądającej autoryzacji za pomocą nazwy użytkownika i hasł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();
                }
            }
        }
    }

0

Zrobiłem to w ten sposób musisz to zrobić po prostu skopiuj wklej to bądź szczęśliwy

    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();
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.