4.5 憑據提供器
憑據提供器意來維護一組用戶憑據,還有能夠對特定認證范圍生產用戶憑據。認證范圍包括主機名,端口號,領域名稱和認證模式名稱。當使用憑據提供器來注冊憑據時,我們可以提供一個通配符(任意主機,任意端口,任意領域,任意模式)來替代確定的屬性值。如果直接匹配沒有發現,憑據提供器期望被用來發現最匹配的特定范圍。
HttpClient可以和任意實現了CredentialsProvider接口的憑據提供器的物理代表一同工作。默認的CredentialsProvider實現被稱為BasicCredentialsProvider,它是簡單的憑借java.util.HashMap的實現。
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("somehost", AuthScope.ANY_PORT),
new UsernamePasswordCredentials("u1", "p1"));
credsProvider.setCredentials(
new AuthScope("somehost", 8080),
new UsernamePasswordCredentials("u2", "p2"));
credsProvider.setCredentials(
new AuthScope("otherhost", 8080, AuthScope.ANY_REALM, "ntlm"),
new UsernamePasswordCredentials("u3", "p3"));
System.out.println(credsProvider.getCredentials(
new AuthScope("somehost", 80, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("somehost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("otherhost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("otherhost", 8080, null, "ntlm")));
輸出內容為:
[principal: u1]
[principal: u2]
null
[principal: u3]
4.6 HTTP認證和執行上下文
HttpClient依賴于AuthState類來跟蹤關于認證過程狀態的詳細信息。在HTTP請求執行過程中,HttpClient創建2個AuthState的實例:一個對于目標主機認證,另外一個對于代理認證。如果目標服務器或代理需要用戶認證,那么各自的AuthState實例將會被在認證處理過程中使用的AuthScope,AuthScheme和Crednetials來填充。AuthState可以被檢查來找出請求的認證是什么類型的,是否匹配AuthScheme的實現,是否憑據提供器對給定的認證范圍去找用戶憑據。
在HTTP請求執行的過程中,HttpClient添加了下列和認證相關的對象到執行上下文中:
- 'http.authscheme-registry':AuthSchemeRegistry實例代表真實的認證模式注冊表。在本地內容中設置的這個屬性的值優先于默認的。
- 'http.auth.credentials-provider':CookieSpec實例代表了真實的憑據提供器。在本地內容中設置的這個屬性的值優先于默認的。
- 'http.auth.target-scope':AuthState實例代表了真實的目標認證狀態。在本地內容中設置的這個屬性的值優先于默認的。
- 'http.auth.proxy-scope':AuthState實例代表了真實的代理認證狀態。在本地內容中設置的這個屬性的值優先于默認的。
本地的HttpContext對象可以用于定制HTTP認證內容,并先于請求執行或在請求被執行之后檢查它的狀態:
HttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
AuthState proxyAuthState = (AuthState) localContext.getAttribute(
ClientContext.PROXY_AUTH_STATE);
System.out.println("Proxy auth scope: " + proxyAuthState.getAuthScope());
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
AuthState targetAuthState = (AuthState) localContext.getAttribute(
ClientContext.TARGET_AUTH_STATE);
System.out.println("Target auth scope: " + targetAuthState.getAuthScope());
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());
4.7 搶占認證
HttpClient不支持開箱的搶占認證,因為濫用或重用不正確的搶占認證可能會導致嚴重的安全問題,比如將用戶憑據以明文形式發送給未認證的第三方。因此,用戶期望評估搶占認證和在它們只能應用程序環境內容安全風險潛在的好處,而且要求使用如協議攔截器的標準HttpClient擴展機制添加對搶占認證的支持。
這是一個簡單的協議攔截器,如果沒有企圖認證,來搶先引入BasicScheme的實例到執行上下文中。請注意攔截器必須在標準認證攔截器之前加入到協議處理鏈中。
HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
public void process(final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(
ClientContext.TARGET_AUTH_STATE);
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
// 如果沒有初始化auth模式
if (authState.getAuthScheme() == null) {
AuthScope authScope = new AuthScope(
targetHost.getHostName(),
targetHost.getPort());
// 獲得匹配目標主機的憑據
Credentials creds = credsProvider.getCredentials(authScope);
// 如果發現了,搶先生成BasicScheme
if (creds != null) {
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
};
DefaultHttpClient httpclient = new DefaultHttpClient();
// 作為第一個攔截器加入到協議鏈中
httpclient.addRequestInterceptor(preemptiveAuth, 0);