Http การรับรองความถูกต้องเบื้องต้นใน Java โดยใช้ HttpClient


156

ฉันพยายามเลียนแบบการทำงานของคำสั่ง curl ใน Java:

curl --basic --user username:password -d "" http://ipaddress/test/login

ฉันเขียนต่อไปนี้โดยใช้ Commons HttpClient 3.0 แต่อย่างใดก็ได้รับ500 Internal Server Errorจากเซิร์ฟเวอร์ บางคนสามารถบอกฉันได้ว่าฉันทำอะไรผิดหรือเปล่า?

public class HttpBasicAuth {

    private static final String ENCODING = "UTF-8";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {

            HttpClient client = new HttpClient();

            client.getState().setCredentials(
                    new AuthScope("ipaddress", 443, "realm"),
                    new UsernamePasswordCredentials("test1", "test1")
                    );

            PostMethod post = new PostMethod(
                    "http://address/test/login");

            post.setDoAuthentication( true );

            try {
                int status = client.executeMethod( post );
                System.out.println(status + "\n" + post.getResponseBodyAsString());
            } finally {
                // release any connection resources used by the method
                post.releaseConnection();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
   } 

และต่อมาฉันก็ลอง Commons HttpClient 4.0.1 แต่ก็ยังมีข้อผิดพลาดเดิมอยู่:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;


public class HttpBasicAuth {

    private static final String ENCODING = "UTF-8";

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        try {
            DefaultHttpClient httpclient = new DefaultHttpClient();

            httpclient.getCredentialsProvider().setCredentials(
                    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), 
                    new UsernamePasswordCredentials("test1", "test1"));

            HttpPost httppost = new HttpPost("http://host:post/test/login");

            System.out.println("executing request " + httppost.getRequestLine());
            HttpResponse response;
            response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            if (entity != null) {
                entity.consumeContent();
            }

            httpclient.getConnectionManager().shutdown();  
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

อืมข้อผิดพลาดที่แสดงในบันทึกเซิร์ฟเวอร์คืออะไร
hvgotcodes

อ่า ... ฉันไม่สามารถเข้าถึงบันทึกเซิร์ฟเวอร์ :(
ตำนาน

ส่วนใหญ่คีย์การอนุญาตที่เราใช้อาจผิด ตรวจสอบdev.tapjoy.com/faq/how-to-find-sender-id-and-api-key-for-gcm เพื่อดูว่าคุณใช้คีย์ที่ถูกต้องหรือไม่ ฉันยังสับสนในขณะที่เลือกคีย์ API สำหรับ firebase เราต้องใช้ SENDER ID - API KEY ในแท็บ Cloud messaging ภายใต้การตั้งค่า firebase เช่นไปที่แอป firebase -> ไปที่การตั้งค่าแอพ -> Cloud Messaging ที่นั่นคุณสามารถหา Sender Id <==> คีย์ API และคีย์ API นี้คุณสามารถใช้เพื่อส่ง FCM
ราหุล

คำตอบ:


187

คุณเคยลองสิ่งนี้ (ใช้ HttpClient เวอร์ชั่น 4):

String encoding = Base64Encoder.encode(user + ":" + pwd);
HttpPost httpPost = new HttpPost("http://host:post/test/login");
httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoding);

System.out.println("executing request " + httpPost.getRequestLine());
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();

64
ดีกว่าที่จะใช้java.util.Base64เป็นของ Java 8:Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Michael Berry

1
ฉันชอบใช้ javax.xml.bind.DatatypeConverter เพื่อทำการแปลงจากเป็น base64, hex และการแปลงอื่น ๆ มันเป็นส่วนหนึ่งของ jdk ดังนั้นไม่จำเป็นต้องรวม JAR เพิ่มเติมใด ๆ
Mubashar

1
นี่เป็นเวอร์ชั่นที่เหมาะกับฉันในกรณีที่ฉันใช้งาน HttpClient มาแล้วและคุณไม่สามารถตั้งค่า setDefaultCredentialsProvider () บนตัวสร้างในขณะที่สร้าง httpclient นอกจากนี้ฉันชอบมันเพราะมันเป็นขอบเขตการโทรต่อ ไม่ได้อยู่ในขอบเขต httpclient ทั้งหมด
โทนี่

114

ตกลงดังนั้นอันนี้ใช้งานได้ ในกรณีที่ใครต้องการมันนี่เป็นเวอร์ชั่นที่เหมาะกับฉัน :)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;


public class HttpBasicAuth {

    public static void main(String[] args) {

        try {
            URL url = new URL ("http://ip:port/login");
            String encoding = Base64.getEncoder().encodeToString(("test1:test1").getBytes(‌"UTF‌​-8"​));

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in   = 
                new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

}

4
Base64Encoderไม่สามารถหา Jonas คุณช่วยมอบไหให้เต็มได้ไหม? ชื่อคลาสที่ผ่านการรับรองแล้วBase64Encoderคืออะไร?
Jus12

@Amitabh: สำหรับBase64Encoderรูปลักษณ์ที่นี่ สำหรับการBase64ค้นหาใน Commons-codec-1.6.jar ใน 4.2.5.zip ที่Apache HttpComponents Downloads , doc ,import org.apache.commons.codec.binary.Base64;
Lernkurve

22
นี่ไม่ได้ตอบคำถาม คำถามถามเกี่ยวกับการใช้ HttpClient และคำตอบนี้ไม่ได้ใช้ HttpClient
Paul Croarkin

9
หากคุณใช้ Java 8 คุณสามารถใช้ java.util.Base64
WW

4
นี่คือบรรทัดสำหรับ java.util.Base64String encoding = Base64.getEncoder().encodeToString("test1:test1".getBytes("utf-8"));
Joe

16

นี่คือรหัสจากคำตอบที่ยอมรับด้านบนโดยมีการเปลี่ยนแปลงบางอย่างเกี่ยวกับการเข้ารหัส Base64 รหัสด้านล่างรวบรวม

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.codec.binary.Base64;


public class HttpBasicAuth {

    public static void main(String[] args) {

        try {
            URL url = new URL ("http://ip:port/login");

            Base64 b = new Base64();
            String encoding = b.encodeAsString(new String("test1:test1").getBytes());

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty  ("Authorization", "Basic " + encoding);
            InputStream content = (InputStream)connection.getInputStream();
            BufferedReader in   = 
                new BufferedReader (new InputStreamReader (content));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } 
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}

14

การอัปเดตเล็ก ๆ - หวังว่าจะมีประโยชน์สำหรับใครบางคน - มันใช้ได้กับฉันในโครงการของฉัน:

  • ฉันใช้ชั้นโดเมนสาธารณะที่ดี Base64.java จาก Robert Harder (ขอบคุณ Robert - รหัส availble ที่นี่: Base64 - ดาวน์โหลดและใส่ไว้ในแพ็คเกจของคุณ)

  • และทำการดาวน์โหลดไฟล์ (รูปภาพ, doc, ฯลฯ ) พร้อมการตรวจสอบความถูกต้องและเขียนไปยังดิสก์ภายในเครื่อง

ตัวอย่าง:

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpBasicAuth {

public static void downloadFileWithAuth(String urlStr, String user, String pass, String outFilePath) {
    try {
        // URL url = new URL ("http://ip:port/download_url");
        URL url = new URL(urlStr);
        String authStr = user + ":" + pass;
        String authEncoded = Base64.encodeBytes(authStr.getBytes());

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setDoOutput(true);
        connection.setRequestProperty("Authorization", "Basic " + authEncoded);

        File file = new File(outFilePath);
        InputStream in = (InputStream) connection.getInputStream();
        OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        for (int b; (b = in.read()) != -1;) {
            out.write(b);
        }
        out.close();
        in.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
}

2
ฉันได้รับThe method encodeBytes(byte[]) is undefined for the type Base64
Francisco Corrales Morales

ชั้น Base64 ที่กำหนดเองสามารถถูกแทนที่ด้วยimport org.apache.commons.codec.binary.Base64; เป็นรายละเอียดในคำตอบนี้ในหน้านี้
แบรดสวนสาธารณะ

3
ใน java 8 คุณสามารถใช้: import java.util.Base64;
WW

7

นี่คือบางจุด:

  • คุณสามารถลองอัปเกรดเป็น HttpClient 4 (โดยทั่วไปถ้าพูดได้ฉันไม่คิดว่าเวอร์ชัน 3 ยังคงรองรับอยู่)

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

  • ฉันคิดว่าsetDoAuthentication(true)เป็นค่าเริ่มต้น (ไม่แน่ใจ) สิ่งที่อาจเป็นประโยชน์ในการลองคือการพิสูจน์ตัวตนแบบ pre-emptive ทำงานได้ดีกว่า:

    client.getParams().setAuthenticationPreemptive(true);

มิฉะนั้นความแตกต่างที่สำคัญระหว่างcurl -d ""และสิ่งที่คุณกำลังทำอยู่ใน Java เป็นที่นอกเหนือไปจากการขดยังส่งContent-Length: 0 Content-Type: application/x-www-form-urlencodedโปรดทราบว่าในแง่ของการออกแบบคุณควรส่งเอนทิตีที่มีการPOSTร้องขอของคุณ


5

ขอบคุณสำหรับคำตอบทั้งหมดข้างต้น แต่สำหรับฉันฉันไม่พบคลาส Base64Encoder ดังนั้นฉันจึงแยกแยะวิธีของฉันต่อไป

public static void main(String[] args) {
    try {
        DefaultHttpClient Client = new DefaultHttpClient();

        HttpGet httpGet = new HttpGet("https://httpbin.org/basic-auth/user/passwd");
        String encoding = DatatypeConverter.printBase64Binary("user:passwd".getBytes("UTF-8"));
        httpGet.setHeader("Authorization", "Basic " + encoding);

        HttpResponse response = Client.execute(httpGet);

        System.out.println("response = " + response);

        BufferedReader breader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuilder responseString = new StringBuilder();
        String line = "";
        while ((line = breader.readLine()) != null) {
            responseString.append(line);
        }
        breader.close();
        String repsonseStr = responseString.toString();

        System.out.println("repsonseStr = " + repsonseStr);

    } catch (IOException e) {
        e.printStackTrace();
    }

}

อีกสิ่งหนึ่งที่ฉันพยายาม

Base64.encodeBase64String("user:passwd".getBytes());

มันไม่ทำงานเนื่องจากมันคืนสตริงเกือบจะเหมือนกัน

DatatypeConverter.printBase64Binary()

แต่ลงท้ายด้วย "\ r \ n" จากนั้นเซิร์ฟเวอร์จะส่งคืน "คำขอที่ไม่ดี"

รหัสต่อไปนี้ก็ใช้งานได้เช่นกันจริงๆแล้วฉันคัดออกมาก่อน แต่ด้วยเหตุผลบางอย่างมันไม่ทำงานในสภาพแวดล้อมคลาวด์ (sae.sina.com.cn หากคุณต้องการทราบว่าเป็นบริการคลาวด์จีน) ดังนั้นจึงต้องใช้ส่วนหัว http แทนข้อมูลประจำตัว HttpClient

public static void main(String[] args) {
    try {
        DefaultHttpClient Client = new DefaultHttpClient();
        Client.getCredentialsProvider().setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials("user", "passwd")
        );

        HttpGet httpGet = new HttpGet("https://httpbin.org/basic-auth/user/passwd");
        HttpResponse response = Client.execute(httpGet);

        System.out.println("response = " + response);

        BufferedReader breader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        StringBuilder responseString = new StringBuilder();
        String line = "";
        while ((line = breader.readLine()) != null) {
            responseString.append(line);
        }
        breader.close();
        String responseStr = responseString.toString();
        System.out.println("responseStr = " + responseStr);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Base64.encodeBase64String ( "ผู้ใช้: passwd" .getBytes ()); ทำงานให้ฉัน DatatypeConverter.printBase64Binary () ใช้ได้สำหรับฉันเช่นกัน อาจเป็นไปได้ว่าคุณทำผิดพลาดกับเนื้อหาของข้อความในกรณีก่อนหน้า หรืออาจจะขึ้นอยู่กับเซิร์ฟเวอร์
ค่าเช่า

5

ในขณะที่ใช้อาร์เรย์ส่วนหัว

String auth = Base64.getEncoder().encodeToString(("test1:test1").getBytes());
Header[] headers = {
    new BasicHeader(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()),
    new BasicHeader("Authorization", "Basic " +auth)
};

3

สำหรับ HttpClient ให้ใช้ HttpRequestInterceptor เสมอ

httclient.addRequestInterceptor(new HttpRequestInterceptor() {
    public void process(HttpRequest arg0, HttpContext context) throws HttpException, IOException {
        AuthState state = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
        if (state.getAuthScheme() == null) {
            BasicScheme scheme = new BasicScheme();
            CredentialsProvider credentialsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
            Credentials credentials = credentialsProvider.getCredentials(AuthScope.ANY);
            if (credentials == null) {
                System.out.println("Credential >>" + credentials);
                throw new HttpException();
            }
            state.setAuthScope(AuthScope.ANY);
            state.setAuthScheme(scheme);
            state.setCredentials(credentials);
        }
    }
}, 0);

3

HttpBasicAuth ใช้ได้กับฉันด้วยการเปลี่ยนแปลงเล็กน้อย

  1. ฉันใช้การพึ่งพา Maven

    <dependency>
        <groupId>net.iharder</groupId>
        <artifactId>base64</artifactId>
        <version>2.3.8</version>
    </dependency>
  2. การเปลี่ยนแปลงเล็กน้อย

    String encoding = Base64.encodeBytes ((user + ":" + passwd).getBytes());

1

วิธีที่ง่ายในการเข้าสู่ระบบด้วย HTTP POST โดยไม่ต้องทำการโทรเฉพาะ Base64 ใด ๆคือการใช้ HTTPClient BasicCredentialsProvider

import java.io.IOException;
import static java.lang.System.out;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;

//code
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, password);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();

HttpResponse response = client.execute(new HttpPost("http://address/test/login"));//Replace HttpPost with HttpGet if you need to perform a GET to login
int statusCode = response.getStatusLine().getStatusCode();
out.println("Response Code :"+ statusCode);

มันไม่ทำงานสำหรับฉัน การโทรทำงานได้ แต่ไม่มีส่วนหัวการรับรองความถูกต้อง
lukas84

แปลกผู้ให้บริการของคุณถูกตั้งค่าอย่างถูกต้อง?
rjdkolb

ลองอัปเดตเวอร์ชันของห้องสมุดของคุณ สิ่งนี้ใช้ได้กับฉัน
rjdkolb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.