Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu cách cấu hình Basic Authentication trong Apache HttpClient 4.
Đầu tiên để sử dụng Apache HttpClient 4 chúng ta cần thêm dependency vào project Maven.
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.4</version> </dependency>
Cấu hình Basic Authentication
Để cấu hình Basic Authentication trong Apache HttpClient chúng ta sẽ cần sử dụng đến CredentialsProvider class.
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.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.HttpClientBuilder; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { String URL_SECURED_BY_BASIC_AUTHENTICATION = "your_url"; String user = "your_user"; String password = "your_password"; 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 HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION)); int statusCode = response.getStatusLine() .getStatusCode(); System.out.println("Status: " + statusCode); } }
Việc cấu hình basic authentication trong Apache không khó, chúng ta chỉ cần cung cấp user-password dùng để đăng nhập cho CredentialsProvider. Các bạn cần lưu ý chỉnh lại URL mà các bạn muốn request, và hãy chắc rằng URL này cần phải xác thực trước đi xử lý request.
Nếu thành công màn hình console của bạn sẽ trông như sau
# ... request is sent with no credentials [main] DEBUG ... - Authentication required [main] DEBUG ... - localhost:8080 requested authentication [main] DEBUG ... - Authentication schemes in the order of preference: [negotiate, Kerberos, NTLM, Digest, Basic] [main] DEBUG ... - Challenge for negotiate authentication scheme not available [main] DEBUG ... - Challenge for Kerberos authentication scheme not available [main] DEBUG ... - Challenge for NTLM authentication scheme not available [main] DEBUG ... - Challenge for Digest authentication scheme not available [main] DEBUG ... - Selected authentication options: [BASIC] # ... the request is sent again - with credentials
Nhìn vào những dòng console in ra ở trên chúng ta có thể suy ra được quá trình giao tiếp giữa Client-Server sẽ diễn ra như sau:
- Client gửi HTTP request mà không đính kèm thông tin đăng nhập
- Server gửi về thông tin thông báo rằng nó cần phải xác thực trước khi xử lý request
- Client chuẩn bị các thông tin cần thiết để xác thực theo tiêu chuẩn mà server đưa ra
- Client gửi lại request kèm theo thông tin xác thực
- Server xử lý và trả về kết quả
Như vậy chúng ta có thể thấy rằng việc này sẽ tốn quá nhiều thời gian để một request có thể hoàn thành khi nó phải gửi đến 2 lần. Do đó, để tối ưu điểm này, chúng ta sẽ sử dụng HttpClientContext để khi một request được gửi nó sẽ đính kèm các thông tin đăng nhập mà không cần phải đợi Server yêu cầu.
import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.HttpClientBuilder; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { String URL_SECURED_BY_BASIC_AUTHENTICATION = "your_url"; String user = "your_user"; String password = "your_password"; HttpHost targetHost = new HttpHost("localhost", 8082, "http"); CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, password)); AuthCache authCache = new BasicAuthCache(); authCache.put(targetHost, new BasicScheme()); HttpClientContext context = HttpClientContext.create(); context.setCredentialsProvider(credsProvider); context.setAuthCache(authCache); HttpClient client = HttpClientBuilder.create().build(); HttpResponse response = client.execute( new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION), context); int statusCode = response.getStatusLine().getStatusCode(); System.out.println("Status: " + statusCode); } }
Lúc này màn hình console sẽ trông giống như thế này
[main] DEBUG ... - Re-using cached 'basic' auth scheme for http://localhost:8082 [main] DEBUG ... - Executing request GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1 [main] DEBUG ... >> GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1 [main] DEBUG ... >> Host: localhost:8082 [main] DEBUG ... >> Authorization: Basic dXNlcjE6dXNlcjFQYXNz [main] DEBUG ... << HTTP/1.1 200 OK [main] DEBUG ... - Authentication succeeded
Không còn việc server yêu cầu client phải đính kèm thông tin đăng nhập vào request, vì vậy chỉ có duy nhất một request được thực hiện trong trường hợp này.
Basic Authentication với HTTP Headers
Đối với cách trên có thể sẽ hơi phức tạp khi chúng ta đang tận dụng mã nguồn của thư viện, có một cách dễ và truyền thống hơn đó là đính kèm thông tin đăng nhập vào HTTP Header.
import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import java.io.IOException; import java.nio.charset.StandardCharsets; public class Main { public static void main(String[] args) throws IOException { String URL_SECURED_BY_BASIC_AUTHENTICATION = "your_url"; String user = "your_user"; String password = "your_password"; HttpGet request = new HttpGet(URL_SECURED_BY_BASIC_AUTHENTICATION); String auth = user + ":" + password; byte[] encodedAuth = Base64.encodeBase64( auth.getBytes(StandardCharsets.ISO_8859_1)); String authHeader = "Basic " + new String(encodedAuth); request.setHeader(HttpHeaders.AUTHORIZATION, authHeader); HttpClient client = HttpClientBuilder.create().build(); HttpResponse response = client.execute(request); int statusCode = response.getStatusLine().getStatusCode(); } }
Output
[main] DEBUG ... - Auth cache not set in the context [main] DEBUG ... - Opening connection {}->http://localhost:8080 [main] DEBUG ... - Connecting to localhost/127.0.0.1:8080 [main] DEBUG ... - Executing request GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1 [main] DEBUG ... - Proxy auth state: UNCHALLENGED [main] DEBUG ... - http-outgoing-0 >> GET /spring-security-rest-basic-auth/api/foos/1 HTTP/1.1 [main] DEBUG ... - http-outgoing-0 >> Authorization: Basic dXNlcjE6dXNlcjFQYXNz [main] DEBUG ... - http-outgoing-0 << HTTP/1.1 200 OK
Trong cả trường hợp URL chúng ta request không yêu cầu thông tin đăng nhập thì cách này vẫn hoạt động bình thường.
Tóm lược
Qua bài viết này chúng ta đã biết cách đính kèm thông tin đăng nhập vào HTTP request trong Apache HttpClient 4. Đây là một cách đơn giản nhưng hiện tại không được khuyến khích sử dụng vì các vấn đề bảo mật.
Nguồn: Baeldung