4.1 用戶憑證
任何用戶身份驗證的過程都需要一組可以用于建立用戶身份的憑據。用戶憑證的最簡單的形式可以僅僅是用戶名/密碼對。UsernamePasswordCredentials代表了一組包含安全規則和明文密碼的憑據。這個實現對由HTTP標準規范中定義的標準認證模式是足夠的
UsernamePasswordCredentials creds = new UsernamePasswordCredentials("user", "pwd");System.out.println(creds.getUserPrincipal().getName());System.out.println(creds.getPassword());
輸出內容為:
userpwd
NTCredentials是微軟Windows指定的實現,它包含了除了用戶名/密碼對外,一組額外的Windows指定的屬性,比如用戶域名的名字,比如在微軟的Windows網絡中,相同的用戶使用不同設置的認證可以屬于不同的域。
NTCredentials creds = new NTCredentials("user", "pwd", "workstation", "domain");System.out.println(creds.getUserPrincipal().getName());System.out.println(creds.getPassword());
輸出內容為:
DOMAIN/userpwd
4.2 認證模式
- 解析和處理由目標服務器在對受保護資源請求的響應中發回的挑戰。
- 提供處理挑戰的屬性:認證模式類型和它的參數,如果可用,比如這個認證模型可應用的領域。
- 對給定的憑證組和HTTP請求對響應真實認證挑戰生成認證字符串。
- Basic(基本):Basic認證模式定義在RFC 2617中。這個認證模式是不安全的,因為憑據以明文形式傳送。盡管它不安全,如果用在和TLS/SSL加密的組合中,Basic認證模式是完全夠用的。
- Digest(摘要):Digest認證模式定義在RFC 2617中。Digest認證模式比Basic有顯著的安全提升,對不想通過TLS/SL加密在完全運輸安全上開銷的應用程序來說也是很好的選擇。
- NTLM:NTLM是一個由微軟開發的優化Windows平臺的專有認證模式。NTLM被認為是比Digest更安全的模式。這個模式需要外部的NTLM引擎來工作。要獲取更多詳情請參考包含在HttpClient發布包中的NTLM_SUPPORT.txt文檔。
4.3 HTTP認證參數
- 'http.protocol.handle-authentication':定義了是否認證應該被自動處理。這個參數期望的得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,HttpClient將會自動處理認證。
- 'http.auth.credential-charset':定義了當編碼用戶憑證時使用的字符集。這個參數期望得到一個java.lang.String類型的值。如果這個參數沒有被設置,那么就會使用US-ASCII。
4.4 認證模式注冊表
- Basic:基本認證模式
- Digest:摘要認證模式
4.5 憑據提供器
憑據提供器意來維護一組用戶憑據,還有能夠對特定認證范圍生產用戶憑據。認證范圍包括主機名,端口號,領域名稱和認證模式名稱。當使用憑據提供器來注冊憑據時,我們可以提供一個通配符(任意主機,任意端口,任意領域,任意模式)來替代確定的屬性值。如果直接匹配沒有發現,憑據提供器期望被用來發現最匹配的特定范圍。
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);// 如果發現了,搶先生成BasicSchemeif (creds != null) {authState.setAuthScheme(new BasicScheme());authState.setCredentials(creds);}}}};DefaultHttpClient httpclient = new DefaultHttpClient();// 作為第一個攔截器加入到協議鏈中httpclient.addRequestInterceptor(preemptiveAuth, 0);
4.8 NTLM 認證
當前HttpClient沒有提對開箱的NTLM認證模式的支持也可能永遠也不會。這個原因是法律上的而不是技術上的。然而,NTLM認證可以使用外部的NTLM引擎比如JCIFS[http://jcifs.samba.org/]來開啟,類庫由Samba[http://www.samba.org/]項目開發,作為它們Windows的交互操作程序套裝的一部分。要獲取詳細內容請參考HttpClient發行包中包含的NTLM_SUPPORT.txt文檔。
4.8.1 NTLM連接持久化
NTLM認證模式是在計算開銷方面昂貴的多的,而且對標準的Basic和Digest模式的性能影響也很大。這很可能是為什么微軟選擇NTLM認證模式為有狀態的主要原因之一。也就是說,一旦認證通過,用戶標識是和連接的整個生命周期相關聯的。NTLM連接的狀態特性使得連接持久化非常復雜,對于明顯的原因,持久化NTLM連接不能被使用不同用戶標識的用戶重用。標準的連接管理器附帶HttpClient是完全能夠管理狀態連接的。而邏輯相關的,使用同一session和執行上下文為了讓它們了解到當前的用戶標識的請求也是極為重要的。否則,HttpClient將會終止對每個基于NTLM保護資源的HTTP請求創建新的HTTP連接。要獲取關于有狀態的HTTP連接的詳細討論,請參考這個部分。
因為NTLM連接是有狀態的,通常建議使用相對簡單的方法觸發NTLM認證,比如GET或HEAD,而重用相同的連接來執行代價更大的方法,特別是它們包含請求實體,比如POST或PUT。
DefaultHttpClient httpclient = new DefaultHttpClient();NTCredentials creds = new NTCredentials("user", "pwd", "myworkstation", "microsoft.com");httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);HttpHost target = new HttpHost("www.microsoft.com", 80, "http");// 保證相同的內容來用于執行邏輯相關的請求HttpContext localContext = new BasicHttpContext();// 首先執行簡便的方法。這會觸發NTLM認證HttpGet httpget = new HttpGet("/ntlm-protected/info");HttpResponse response1 = httpclient.execute(target, httpget, localContext);HttpEntity entity1 = response1.getEntity();if (entity1 != null) {entity1.consumeContent();}//之后使用相同的內容(和連接)執行開銷大的方法。HttpPost httppost = new HttpPost("/ntlm-protected/form");httppost.setEntity(new StringEntity("lots and lots of data"));HttpResponse response2 = httpclient.execute(target, httppost, localContext);HttpEntity entity2 = response2.getEntity();if (entity2 != null) {entity2.consumeContent();}
轉載自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113247.html