1. 程式人生 > >《HttpClient官方文件》HTTP驗證4.4-4.7

《HttpClient官方文件》HTTP驗證4.4-4.7

原文連結: 譯者:Edenpan

4.4 HTTP驗證和執行上下文

HttpClient依賴於AuthState類來追蹤驗證程序的狀態的詳細資訊。HttpClient在執行HTTP請求執行時,建立AuthState的兩個例項:一個對目標主機認證,另外一個用於代理認證。一旦目標主機或者代理要求使用者驗證,對應的AuthState例項將會在驗證過程中被AuthScope,AuthScheme和Crednetials填充。這個AuthState可以被檢查用於找出哪種型別要求驗證,是否對應的AuthScheme被找到,以及憑證提供者可以找到在給定的驗證範圍內找到使用者憑證。


在HTTP請求過程中HttpClient添加了以下的驗證關係物件到執行上下文中:

  • Lookup 例項代表實際的驗證方案註冊。這個屬性值在本地上下文中優先與預設值被設定。
  • CredentialsProvider例項代表實際的憑證提供者。這個屬性值本地上下文中優先與預設值被設定。
  • AuthState例項代表實際的目標驗證狀態。這個屬性值本地上下文中優先與預設值被設定。
  • AuthState例項代表實際的代理驗證狀態。這個屬性值本地上下文中優先與預設值被設定。
  • AuthCache例項代表實際的驗證資料快取。這個屬性值本地上下文中優先與預設值被設定。

這個本地的HttpContext物件可以在請求執行之前定製HTTP驗證上下文或者在請求被執行後檢查它的狀態:

CloseableHttpClient httpclient = <...>
CredentialsProvider credsProvider = <...>
Lookup<AuthSchemeProvider> authRegistry = <...>
AuthCache authCache = <...>
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthSchemeRegistry(authRegistry);
context.setAuthCache(authCache);
HttpGet httpget = new HttpGet("http://somehost/");
CloseableHttpResponse response1 = httpclient.execute(httpget, context);
<...>
AuthState proxyAuthState = context.getProxyAuthState();
System.out.println("Proxy auth state: " + proxyAuthState.getState());
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
AuthState targetAuthState = context.getTargetAuthState();
System.out.println("Target auth state: " + targetAuthState.getState());
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());

4.5 驗證資料快取

從4.1版本開始HttpClient自動快取驗證成功的主機的資訊。請注意為了使快取的驗證資料從一個請求傳播到另外一個請求上,必須使用相同的上下文來執行相關的邏輯請求。如果執行上下文超出了範圍,驗證資料將會很快丟失。

4.6 搶佔式驗證

HttpClient 不支援搶佔試驗證因為如果錯誤使用搶佔式驗證會導致明顯的安全問題,比如明文傳送使用者憑證到第三方沒有驗證的組織。除此之外使用者被期望在他們自己的應用環境中自己來評估搶佔式驗證的潛在好處和安全風險。
儘管如此可以通過配置HttpClient預填充驗證資料到緩衝中來實現搶佔式驗證。
CloseableHttpClient httpclient = <…>

HttpHost targetHost = new HttpHost("localhost", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
        new AuthScope(targetHost.getHostName(), targetHost.getPort()),
        new UsernamePasswordCredentials("username", "password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);

// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);
HttpGet httpget = new HttpGet("/");
for (int i = 0; i < 3; i++) {
    CloseableHttpResponse response = httpclient.execute(
            targetHost, httpget, context);
    try {
        HttpEntity entity = response.getEntity();
    } finally {
        response.close();
    }
}

4.7 NTLM驗證

自從4.1HttpClient版本對NTLMv1, NTLMv2, and NTLM2會話驗證提供完全的支援。外部的NTML引擎比如由Samba專案開發的JCIFS庫作為其Windows互操作性程式套件的一部分仍然可以被使用。

4.7.1 NTLM連線持久化

NTLM驗證方案比標準的Basic和Digest方案要明顯消耗更多的計算效能。這也許是微軟選擇使NTLM驗證方案狀態話的主要原因。只要驗證成功了,這個使用者的標誌會和它整個連線的壽命相關。NTLM有狀態的特性使連線持久化更加複雜,一個明顯的原因:連線持久化的NTLM不能被不同的使用者標識進行重用。無論如何在同一個會話中邏輯相關的請求使用相同的執行上下文來保證它們意識到當前使用者的身份。否則HttpClient將會針對每一個NTLM保護請求的每一個Http請求建立一個新的HTTP連線。對於狀態話的HTTP請求的詳細討論請參考這個頁面
由於NTLM是狀態話的,它一般推薦使用相對便宜的方式來觸發NTLM驗證,比如GET或者HEAD,以及複用相同的連線來執行更加昂貴的操作,特別是包含了請求實體的比如POST或者PUT。

CloseableHttpClient httpclient = <...>
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
        new NTCredentials("user", "pwd", "myworkstation", "microsoft.com"));

HttpHost target = new HttpHost("www.microsoft.com", 80, "http");

// Make sure the same context is used to execute logically related requests
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);

// Execute a cheap method first. This will trigger NTLM authentication
HttpGet httpget = new HttpGet("/ntlm-protected/info");
CloseableHttpResponse response1 = httpclient.execute(target, httpget, context);
try {
    HttpEntity entity1 = response1.getEntity();
} finally {
    response1.close();
}

// Execute an expensive method next reusing the same context (and connection)
HttpPost httppost = new HttpPost("/ntlm-protected/form");
httppost.setEntity(new StringEntity("lots and lots of data"));
CloseableHttpResponse response2 = httpclient.execute(target, httppost, context);
try {
    HttpEntity entity2 = response2.getEntity();
} finally {
    response2.close();
}