Menghubungkan ke URL jarak jauh yang membutuhkan otentikasi menggunakan Java


125

Bagaimana cara menyambung ke URL jarak jauh di Java yang memerlukan otentikasi. Saya mencoba menemukan cara untuk mengubah kode berikut agar dapat memberikan nama pengguna / kata sandi secara terprogram sehingga tidak memunculkan 401.

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

Jawaban:


134

Anda dapat menyetel pengautentikasi default untuk permintaan http seperti ini:

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

Selain itu, jika Anda membutuhkan lebih banyak fleksibilitas, Anda dapat memeriksa Apache HttpClient , yang akan memberi Anda lebih banyak opsi otentikasi (serta dukungan sesi, dll.)


4
Bagaimana Anda menangani peristiwa otentikasi yang buruk? [Misalnya, jika pengguna memberikan nama pengguna dan kredensial otentikasi sandi yang tidak cocok dengan apapun]?
SK9

2
Kode di atas berfungsi tetapi cukup implisit tentang apa yang terjadi. Ada subclass dan metode overriding yang terjadi di sana, gali dokumen untuk kelas-kelas itu jika Anda peduli untuk mengetahui apa yang terjadi. Kode di sini adalah javacodegeeks yang
Fuchida

12
Apakah mungkin untuk menyetel spesifik Authenticatorper URL.openConnection()permintaan tertentu daripada menyetelnya secara global?
Yuriy Nakonechnyy

@Yura: tidak. Ini harus global. Namun, Anda dapat melakukan hal-hal jahat seperti menyetel pengautentikasi global yang menarik kredensial dari variabel lokal-thread, dan menyetel kredensial per thread sebelum membuat koneksi HTTP.
David Diberikan

4
Menanggapi @YuriyNakonechnyy ... jika Anda menggunakan Java 9 atau lebih tinggi maka Anda dapat menelepon HttpURLConnection.setAuthenticator(). Sayangnya di Java 8 dan sebelumnya, instance Authenticator adalah variabel global seluruh JVM. Lihat: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett

133

Ada alternatif asli dan tidak terlalu mengganggu, yang hanya berfungsi untuk panggilan Anda.

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
Kelas Base64 dapat disediakan oleh Apache Commons Codec.
Matthew Buckett

Tidak berhasil untuk saya seperti ini ... Hanya cara @James Van Huis yang baik
Miguel Ribeiro

Ini 'asli' di Grails dan banyak kerangka kerja Java lainnya karena semuanya menggunakan Apache Commons Libs.
Wanderson Santos

1
Tidak berfungsi secara umum kecuali Anda .trim()adalah hasilnya, atau memanggil varian metode yang tidak menghasilkan keluaran yang dipotong. javax.xml.bind.DatatypeConvertertampaknya lebih aman.
Jesse Glick

Saya mengutip kode Anda dalam jawaban ini Terima kasih
notes-jj

77

Anda juga dapat menggunakan berikut ini, yang tidak memerlukan penggunaan paket eksternal:

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
Saya sudah lama mencari encoder Base64 di dalam paket standar java! Terima kasih
qwertzguy

Perhatikan bahwa untuk Java9 + Anda mungkin harus melakukannya --add-modules javax.xml.bindkarena mereka menghapus paket dari classpath default. Dan di Java11 + itu dihapus sama sekali, Anda membutuhkan ketergantungan eksternal lagi. Begitulah kemajuan!
Ed Randall

1
@EdRandall ada java.util.Base64sekarang jadi memang kemajuan :)
Steven Schlansker

42

Jika Anda menggunakan login normal sambil memasukkan nama pengguna dan kata sandi antara protokol dan domain, ini lebih sederhana. Ia juga bekerja dengan dan tanpa login.

Contoh Url: http: // pengguna: 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();

Harap perhatikan dalam komentar, dari valerybodak, di bawah ini bagaimana hal itu dilakukan dalam lingkungan pengembangan Android.


1
Ini persis seperti yang saya cari selama 30 menit terakhir. Terima kasih banyak!
Geert Schuring

Jika nama pengguna / kata sandi Anda mengandung karakter khusus, saya yakin Anda perlu meng-urlencode itu. Kemudian, dalam potongan kode di atas, Anda akan melewati url.getUserInfo()thorugh URLDecoder.decode()pertama (@ Peter Rader).
m01

Terima kasih, tetapi untuk android Anda harus menggunakan Base64 sebagai berikut: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). GetBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("Authorization", basicAuth);
valerybodak

Terima kasih valerybodak untuk pelengkap itu!
javabeangrinder

8

Karena saya datang ke sini untuk mencari Android-Java-Answer, saya akan membuat ringkasan singkat:

  1. Gunakan java.net.Authenticator seperti yang ditunjukkan oleh James van Huis
  2. Gunakan Klien HTTP Apache Commons , seperti dalam Jawaban ini
  3. Gunakan java.net.URLConnection dasar dan atur Authentication-Header secara manual seperti yang ditunjukkan di sini

Jika Anda ingin menggunakan java.net.URLConnection dengan Otentikasi Dasar di Android coba kode ini:

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
Terima kasih. Sedang mencari jawaban khusus Android!
Stephen McCormick

5

Mampu menyetel auth menggunakan 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);

beberapa perubahan diambil dari postingan ini. dan Base64 dari paket java.util.


3

Berhati-hatilah dengan pendekatan "Base64 (). Encode ()", tim saya dan saya mendapat 400 masalah permintaan buruk Apache karena menambahkan \ r \ n di akhir string yang dihasilkan.

Kami menemukannya mengendus paket berkat Wireshark.

Inilah solusi kami:

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

Semoga membantu!


3

Gunakan kode ini untuk otentikasi dasar.

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

Saya ingin memberikan jawaban untuk kasus di mana Anda tidak memiliki kendali atas kode yang membuka koneksi. Seperti yang saya lakukan saat menggunakan URLClassLoaderuntuk memuat file jar dari server yang dilindungi kata sandi.

The Authenticatorsolusi akan bekerja tapi memiliki kekurangan yang pertama kali mencoba untuk mencapai server tanpa password dan hanya setelah server meminta password menyediakan satu. Itu adalah perjalanan bolak-balik yang tidak perlu jika Anda sudah mengetahui bahwa server memerlukan kata sandi.

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

}

Ini mendaftarkan protokol baru myyang diganti httpsaat kredensial ditambahkan. Jadi saat membuat yang baru URLClassLoaderganti saja httpdengan mydan semuanya baik-baik saja. Saya tahu URLClassLoadermenyediakan konstruktor yang membutuhkan URLStreamHandlerFactorytetapi pabrik ini tidak digunakan jika URL mengarah ke file jar.


1

Sejak Java 9, Anda dapat melakukan ini

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
Belum melihat setAuthenticator()metode.
WesternGun

0

IMPLEMENTASI ANDROD Sebuah metode lengkap untuk meminta respon data / string dari layanan web meminta otorisasi dengan nama pengguna dan kata sandi

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

Saya melakukan itu dengan cara ini Anda perlu melakukan ini, cukup salin tempel, itu akan bahagia

    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();
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.