การเชื่อมต่อกับรีโมต URL ซึ่งต้องการการพิสูจน์ตัวตนโดยใช้ Java


128

ฉันจะเชื่อมต่อกับ URL ระยะไกลใน Java ซึ่งต้องมีการพิสูจน์ตัวตนได้อย่างไร ฉันกำลังพยายามหาวิธีแก้ไขรหัสต่อไปนี้เพื่อให้สามารถระบุชื่อผู้ใช้ / รหัสผ่านโดยทางโปรแกรมเพื่อไม่ให้เกิด 401

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

ตรวจสอบที่นี่: stackoverflow.com/questions/1359689/…
WesternGun

คำตอบ:


136

คุณสามารถตั้งค่าตัวรับรองความถูกต้องเริ่มต้นสำหรับคำขอ http ดังนี้:

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

นอกจากนี้หากคุณต้องการความยืดหยุ่นมากขึ้นคุณสามารถตรวจสอบApache HttpClientซึ่งจะให้ตัวเลือกการรับรองความถูกต้องเพิ่มเติมแก่คุณ (เช่นเดียวกับการสนับสนุนเซสชัน ฯลฯ )


4
คุณจัดการกับเหตุการณ์การตรวจสอบสิทธิ์ที่ไม่ถูกต้องได้อย่างไร [ตัวอย่างเช่นหากผู้ใช้ให้ข้อมูลรับรองการตรวจสอบชื่อผู้ใช้และรหัสผ่านที่ไม่ตรงกับอะไรเลย]?
SK9

2
รหัสข้างต้นใช้งานได้ แต่ค่อนข้างมีนัยว่าเกิดอะไรขึ้น มีคลาสย่อยและวิธีการลบล้างที่เกิดขึ้นขุดลงในเอกสารสำหรับชั้นเรียนเหล่านั้นหากคุณต้องการทราบว่าเกิดอะไรขึ้น รหัสที่นี่คือjavacodegeeks ที่
Fuchida

12
เป็นไปได้ไหมที่จะตั้งค่าเฉพาะAuthenticatorสำหรับURL.openConnection()การร้องขอที่เจาะจงแทนที่จะตั้งค่าทั่วโลก
Yuriy Nakonechnyy

@ ยูรา: ไม่. มันต้องเป็นระดับโลก อย่างไรก็ตามคุณสามารถทำสิ่งชั่วร้ายเช่นการตั้งค่า global authenticator ซึ่งดึงข้อมูลประจำตัวออกจากตัวแปร thread-local และตั้งค่าข้อมูลประจำตัวต่อเธรดก่อนทำการเชื่อมต่อ HTTP
David Given

4
เพื่อตอบสนองต่อ @YuriyNakonechnyy ... หากคุณใช้ Java 9 ขึ้นไปคุณสามารถโทรHttpURLConnection.setAuthenticator(). น่าเสียดายที่ใน Java 8 และรุ่นก่อนหน้านั้นอินสแตนซ์ Authenticator เป็นตัวแปรส่วนกลางทั่วทั้ง JVM ดู: docs.oracle.com/javase/9/docs/api/java/net/…
Neil Bartlett

134

มีทางเลือกแบบเนทีฟและรบกวนน้อยกว่าซึ่งใช้ได้กับการโทรของคุณเท่านั้น

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
คลาส Base64 สามารถจัดเตรียมโดย Apache Commons Codec
Matthew Buckett

ไม่ได้ผลสำหรับฉันด้วยวิธีนี้ ... เฉพาะวิธีที่ @James Van Huis ดี
Miguel Ribeiro

มันเป็น 'เนทีฟ' บน Grails และเฟรมเวิร์ก Java อื่น ๆ อีกมากมายเพราะพวกเขาทั้งหมดใช้ Apache Commons Libs
Wanderson Santos

1
ไม่ทำงานโดยทั่วไปเว้นแต่คุณจะได้.trim()ผลลัพธ์หรือเรียกใช้ตัวแปรวิธีการที่ไม่สร้างผลลัพธ์ที่เป็นก้อน javax.xml.bind.DatatypeConverterดูเหมือนจะปลอดภัยกว่า
Jesse Glick

ฉันอ้างรหัสของคุณในคำตอบนี้ ขอบคุณ
บันทึก -jj

78

คุณยังสามารถใช้สิ่งต่อไปนี้ซึ่งไม่จำเป็นต้องใช้แพ็คเกจภายนอก:

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
ฉันมองหาตัวเข้ารหัส Base64 ในแพ็คเกจมาตรฐาน java มานานแล้ว! ขอบคุณ
qwertzguy

โปรดทราบว่าสำหรับ Java9 + คุณอาจต้องทำ--add-modules javax.xml.bindเนื่องจากพวกเขาลบแพ็คเกจออกจากคลาสพา ธ เริ่มต้น และใน Java11 + จะถูกลบออกไปทั้งหมดคุณต้องมีการพึ่งพาภายนอกอีกครั้ง นั่นคือความคืบหน้า!
Ed Randall

1
@EdRandall java.util.Base64ตอนนี้มีความคืบหน้าแน่นอน :)
Steven Schlansker

42

หากคุณใช้การเข้าสู่ระบบปกติในขณะที่ป้อนชื่อผู้ใช้และรหัสผ่านระหว่างโปรโตคอลและโดเมนสิ่งนี้จะง่ายกว่า นอกจากนี้ยังใช้งานได้โดยไม่ต้องเข้าสู่ระบบ

ตัวอย่าง URL: http: // user: 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();

โปรดทราบในความคิดเห็นจาก valerybodak ด้านล่างวิธีการทำงานในสภาพแวดล้อมการพัฒนา Android


1
นี่คือว่าสิ่งที่ฉันได้รับการค้นหาที่ผ่านมา 30 นาที ขอบคุณมาก!
Geert Schuring

หากชื่อผู้ใช้ / รหัสผ่านของคุณมีอักขระพิเศษฉันเชื่อว่าคุณจะต้อง urlencode เหล่านั้น จากนั้นในส่วนย่อยของโค้ดด้านบนคุณจะต้องผ่านurl.getUserInfo()thorugh URLDecoder.decode()ก่อน (@Peter Rader)
m01

ขอบคุณ แต่สำหรับ Android คุณควรใช้ Base64 ดังต่อไปนี้: String basicAuth = "Basic" + Base64.encodeToString (url.getUserInfo (). getBytes (), Base64.DEFAULT); httpConn.setRequestProperty ("การอนุญาต", basicAuth);
valerybodak

ขอบคุณ valerybodak สำหรับส่วนเสริมนั้น!
javabeangrinder

8

เนื่องจากฉันมาที่นี่เพื่อค้นหาคำตอบ Android-Java ฉันจะสรุปสั้น ๆ :

  1. ใช้java.net.Authenticatorตามที่James van Huis แสดง
  2. ใช้Apache Commons HTTP Clientดังในคำตอบนี้
  3. ใช้java.net.URLConnectionพื้นฐานและตั้งค่า Authentication-Header ด้วยตนเองดังที่แสดงไว้ที่นี่

หากคุณต้องการใช้java.net.URLConnectionกับ Basic Authentication ในAndroidให้ลองใช้รหัสนี้:

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
ขอบคุณ กำลังมองหาคำตอบเฉพาะสำหรับ Android!
Stephen McCormick

5

สามารถตั้งค่าการรับรองความถูกต้องโดยใช้ 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);

การเปลี่ยนแปลงบางอย่างที่ดึงมาจากโพสต์นี้ และ Base64 มาจากแพ็คเกจ java.util


3

โปรดใช้ความระมัดระวังอย่างยิ่งกับแนวทาง "Base64 (). encode ()" ทีมของฉันและฉันพบปัญหาเกี่ยวกับคำขอที่ไม่ถูกต้องของ Apache 400 รายการเนื่องจากมีการเพิ่ม \ r \ n ที่ท้ายสตริงที่สร้างขึ้น

เราพบว่ามันกำลังดมแพ็คเก็ตด้วย Wireshark

นี่คือทางออกของเรา:

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

หวังว่าจะช่วยได้!


3

ใช้รหัสนี้สำหรับการพิสูจน์ตัวตนพื้นฐาน

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

ฉันต้องการให้คำตอบสำหรับกรณีที่คุณไม่สามารถควบคุมรหัสที่เปิดการเชื่อมต่อได้ เช่นเดียวกับที่ฉันทำเมื่อใช้URLClassLoaderเพื่อโหลดไฟล์ jar จากเซิร์ฟเวอร์ที่ป้องกันด้วยรหัสผ่าน

Authenticatorวิธีการแก้ปัญหาจะทำงาน แต่มีข้อเสียเปรียบที่มันเป็นครั้งแรกพยายามที่จะเข้าถึงเซิร์ฟเวอร์โดยไม่ต้องใช้รหัสผ่านและหลังจากเซิร์ฟเวอร์ขอรหัสผ่านให้เป็นหนึ่ง เป็นการไปกลับที่ไม่จำเป็นหากคุณรู้อยู่แล้วว่าเซิร์ฟเวอร์จะต้องใช้รหัสผ่าน

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

}

สิ่งนี้จะลงทะเบียนโปรโตคอลใหม่myที่ถูกแทนที่ด้วยhttpเมื่อมีการเพิ่มข้อมูลรับรอง ดังนั้นเมื่อสร้างใหม่ให้URLClassLoaderแทนที่httpด้วยmyและทุกอย่างเรียบร้อยดี ฉันรู้ว่าURLClassLoaderมีตัวสร้างที่ใช้URLStreamHandlerFactoryแต่โรงงานนี้ไม่ได้ใช้หาก URL ชี้ไปที่ไฟล์ jar


1

ตั้งแต่ Java 9 คุณสามารถทำได้

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
ยังไม่เห็นsetAuthenticator()วิธีการ
WesternGun

0

การดำเนินการ ANDROD วิธีการที่สมบูรณ์ในการร้องขอการตอบกลับข้อมูล / สตริงจากบริการเว็บที่ขอการอนุญาตด้วยชื่อผู้ใช้และรหัสผ่าน

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

ฉันทำแบบนี้คุณต้องทำสิ่งนี้เพียงแค่คัดลอกวางก็มีความสุข

    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();
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.