自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Apache HttpClient突破J2EE站點(diǎn)認(rèn)證

開發(fā) 后端
商業(yè)性 Web 站點(diǎn)大都提供站點(diǎn)認(rèn)證功能以保護(hù)某些受限資源,HTTP 協(xié)議和 J2EE 規(guī)范對(duì) Web 站點(diǎn)的認(rèn)證過程都已有了詳盡的定義,常見瀏覽器都能根據(jù)相應(yīng)協(xié)議提供對(duì)應(yīng)的界面形式幫助用戶完成站點(diǎn)的認(rèn)證過程。但在某些情況下,我們需要編寫程序直接獲取站點(diǎn)的受保護(hù)資源,在這類情況下,就不能利用瀏覽器給定的界面去完成認(rèn)證,而需要我們根據(jù)不同的協(xié)議人工地發(fā)送相應(yīng)請(qǐng)求以完成整個(gè)認(rèn)證過程。本文根據(jù)這種需求給出一個(gè)基于 Apache HttpClient 應(yīng)用包的解決方案。

J2EE 站點(diǎn)認(rèn)證簡(jiǎn)介

出于安全性的需要和用戶授權(quán)管理的考慮,常見的 J2EE 站點(diǎn)對(duì)特定資源都會(huì)加入認(rèn)證/授權(quán)機(jī)制。例如一個(gè)公網(wǎng)上的論壇,一個(gè)只對(duì)特定用戶開放的 RSS 或 Atom Feed,這些資源都必須在確信訪問者為被授權(quán)用戶時(shí)才能向訪問者開放。為了實(shí)現(xiàn)這樣的功能,J2EE 站點(diǎn)通常會(huì)采用某種站點(diǎn)認(rèn)證機(jī)制,其中常見的有 HTTP Basic 認(rèn)證和 J2EE Form-Based 認(rèn)證。

HTTP Basic 認(rèn)證

HTTP Basic 認(rèn)證是 HTTP 認(rèn)證協(xié)議(rfc2617)所定義的標(biāo)準(zhǔn)認(rèn)證方式。要求 HTTP Basic 認(rèn)證的服務(wù)器會(huì)在客戶端訪問受保護(hù)資源時(shí)向客戶端發(fā)出請(qǐng)求,要求客戶端上傳用戶名和密碼對(duì)。服務(wù)器在收到用戶名/密碼并驗(yàn)證通過后,才將保護(hù)資源的內(nèi)容返回給客戶端。它的工作機(jī)制如下圖:

圖 1. HTTP Basic 認(rèn)證原理

圖 1. HTTP Basic 認(rèn)證原理 

由于是 HTTP 規(guī)范,因而常見的瀏覽器,如 Internet Explorer,Mozilla Firefox,在 步驟 2 中收到服務(wù)器對(duì)用戶名和密碼的請(qǐng)求時(shí)會(huì)彈出認(rèn)證對(duì)話框,供用戶輸入用戶名/密碼。

圖 2. Firefox 在收到步驟 2 中請(qǐng)求時(shí)彈出的用戶名/密碼輸入框

圖 2. Firefox 在收到步驟 2 中請(qǐng)求時(shí)彈出的用戶名/密碼輸入框 

HTTP Basic 認(rèn)證方式使用 base64 編碼方式傳送用戶名和密碼,而 base64 僅僅是一種公開的編碼格式而非加密措施,因而如果信道本身不使用 SSL 等安全協(xié)議,用戶密碼較容易被截獲。

J2EE Form-Based 認(rèn)證

Form-Based 認(rèn)證不同于 HTTP Basic 認(rèn)證,它是 J2EE 對(duì)于認(rèn)證方式的一種擴(kuò)展。它使用自定義的 HTML 表單(通常為 login.jsp)作為輸入用戶名和密碼的用戶界面,最終將用戶在表單上填入的用戶名/密碼提交至服務(wù)器。它的工作機(jī)制如下:

圖 3. Form-Based 認(rèn)證原理

圖 3. Form-Based 認(rèn)證原理 

Form-Based 認(rèn)證方式在 J2EE 站點(diǎn)中更為常見。這一方面是由于它提供了自定義的用戶名密碼輸入界面;另一方面它的傳輸也更為安全,通常情況下 login.jsp 會(huì)被配置為需要使用 SSL 信道訪問,這樣在步驟 2、3 中對(duì)用戶名和密碼的傳送就被安全信道所保護(hù),而較難被非法截取。

Apache HttpClient 認(rèn)證功能簡(jiǎn)介

Apache HttpClient 是 Apache 開源組織提供的純 Java 實(shí)現(xiàn)的 HTTP 開源包。它能模擬各類 HTTP 客戶端所需功能,例如 HTTP/HTTPS 連接,GET/PUT 請(qǐng)求,甚至提供了超時(shí)重試的功能。

HttpClient 也提供了對(duì)標(biāo)準(zhǔn) HTTP 認(rèn)證的接口,在最新的 HttpClient 3.1 中,支持的認(rèn)證方式有:

  • Basic 認(rèn)證:即前面提到的 rfc2716 規(guī)范中定義的 HTTP Basic 認(rèn)證方式。
  • Digest 認(rèn)證:一種基于摘要的更為安全的認(rèn)證協(xié)議,雖然它的應(yīng)用沒有 Basic 認(rèn)證方式廣泛。
  • NTLM 認(rèn)證:微軟制定的認(rèn)證協(xié)議規(guī)范,然而此項(xiàng)標(biāo)準(zhǔn)的細(xì)節(jié)卻并不公開。

我們可以注意到 Form-Based 認(rèn)證并不在其中,這是因?yàn)?Form-Based 認(rèn)證方式并非 HTTP 協(xié)議標(biāo)準(zhǔn),而是 J2EE 提供的一種特殊的認(rèn)證方式,因而開發(fā)者需要在 HttpClient 基礎(chǔ)上另行開發(fā)適合 Form-Based 認(rèn)證的方案。

使用 Apache HttpClient 通過 HTTP Basic 認(rèn)證

由于 HttpClient 內(nèi)置支持 HTTP Basic 認(rèn)證方式,因而使用 HttpClient 通過 HTTP Basic 認(rèn)證的步驟顯得較為簡(jiǎn)單。

  1. 為 HttpClient 的狀態(tài)對(duì)象添加用戶名/密碼對(duì)。可以注意到在 setCredentials 方法中的另一個(gè)參數(shù)為 AuthScope 對(duì)象。事實(shí)上我們添加的每個(gè)用戶名/密碼對(duì)都與一個(gè) AuthScope 對(duì)象相關(guān)聯(lián)。AuthScope 對(duì)象確定了此用戶名/密碼對(duì)的適用站點(diǎn),在示例中所給出的用戶名/密碼對(duì)將只適用于 www.sample.com 位于 80 端口上的資源。HttpClient 在與其他站點(diǎn)交互時(shí)將不會(huì)使用此用戶名/密碼對(duì),這樣有效地防止了機(jī)密數(shù)據(jù)被傳送至不必要的站點(diǎn)。
  2. 開啟 HttpClient 提供的占先式(Preemptive)認(rèn)證功能。開啟了這個(gè)功能后,HttpClient 對(duì)于那些處在之前請(qǐng)求過的URI空間范圍內(nèi)的資源,會(huì)主動(dòng)地隨請(qǐng)求一起向服務(wù)器發(fā)送 Basic 認(rèn)證數(shù)據(jù),而不是等待服務(wù)器返回是否需要認(rèn)證的響應(yīng)后再提交認(rèn)證。在多數(shù)情況下,能夠減少請(qǐng)求-響應(yīng)傳遞的次數(shù),從而間接提高了服務(wù)器的響應(yīng)能力。值得注意的是在這種情況下必須在 AuthScope 對(duì)象中明確指定適用站點(diǎn),以避免向不相關(guān)的站點(diǎn)泄漏敏感數(shù)據(jù)。
  3. 創(chuàng)建 GetMethod 對(duì)象,此對(duì)象將使用 GET 方式對(duì)保護(hù)資源發(fā)出 HTTP 請(qǐng)求。
  4. setDoAuthentication(true) 語(yǔ)句將告知 HttpClient 在服務(wù)器端發(fā)回需要認(rèn)證的請(qǐng)求后,自動(dòng)將我們?cè)诓襟E 1 中設(shè)置的用戶名/密碼對(duì)發(fā)送至服務(wù)器,以完成認(rèn)證過程。

執(zhí)行 GET 請(qǐng)求,獲取和處理受保護(hù)資源的內(nèi)容。

清單 1. Basic 認(rèn)證示例

  1.                   
  2. HttpClient client = new HttpClient();  
  3.       
  4. // 1  
  5. client.getState().setCredentials(  
  6.     new AuthScope("www.sample.com"80, AuthScope.ANY_REALM),  
  7.     new UsernamePasswordCredentials("username""password")  
  8. );  
  9.            
  10. // 2  
  11. client.getParams().setAuthenticationPreemptive(true);  
  12.  
  13. // 3  
  14. GetMethod get = new GetMethod("http://www.sample.com/protected.html");  
  15.  
  16. // 4  
  17. get.setDoAuthentication( true );  
  18.  
  19. try {  
  20.     // 5  
  21.     int status = client.executeMethod( get );  
  22.  
  23.     // process the content from the response  
  24.     …  
  25.  
  26. finally {  
  27.     get.releaseConnection();  

由于 Basic 認(rèn)證方式直接向服務(wù)器發(fā)送未經(jīng)加密的用戶名/密碼對(duì),導(dǎo)致這些敏感數(shù)據(jù)很容易在網(wǎng)絡(luò)傳輸過程中被截取,因此安全性很低。所幸 HttpClient 對(duì)基于安全套接字層(SSL)的 HTTP 協(xié)議(HTTPS)提供了足夠的支持,而且使用起來也很簡(jiǎn)單。不過之前需確保本地機(jī)器已經(jīng)安裝好 JSSE(Sun 提供的 JDK 1.4 及之后的版本已集成 JSSE)。

使用 HttpClient 進(jìn)行標(biāo)準(zhǔn)的 SSL 連接對(duì)用戶來說是透明的。參照清單 1,用戶只需用符合 HTTPS 協(xié)議的 URL 作為參數(shù)生成 GetMethod 對(duì)象即可。除此之外,HttpClient 還允許用戶定制 SSL 使得客戶端程序能夠自動(dòng)接受不同類型的證書。

利用 HttpClient 實(shí)現(xiàn)一個(gè)自定義的 SSL 協(xié)議包括以下 3 個(gè)關(guān)鍵步驟:

  1. 定制一個(gè)實(shí)現(xiàn)了 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory 接口的工廠類。這個(gè)工廠類的作用是開啟一個(gè)與服務(wù)器通訊的 Socket 并進(jìn)行必需的初始化動(dòng)作。關(guān)于實(shí)現(xiàn)該接口的具體細(xì)節(jié),HttpClient 項(xiàng)目的主頁(yè)上有詳細(xì)的代碼實(shí)例和注釋說明。
  2. 利用之前創(chuàng)建的工廠類對(duì)象、HTTPS 協(xié)議名稱和默認(rèn)端口號(hào)實(shí)例化一個(gè)新的 org.apache.commons.httpclient.protocol.Protocol 對(duì)象。
  3. 注冊(cè)這個(gè)自定義的 Protocol 對(duì)象使其與某個(gè)協(xié)議名綁定,當(dāng) HttpClient 處理此類協(xié)議時(shí),將默認(rèn)調(diào)用這個(gè)自定義 Protocol 對(duì)象。

清單 2. 在 HttpClient 中自定義 SSL 示例

  1. // 1  
  2. SecureProtocolSocketFactory sampleSSLSocketFactory = new SampleSSLSocketFactory();  
  3.       
  4. // 2  
  5. Protocol httpsProtocol = new Protocol("https", sampleSSLSocketFactory, 443);  
  6.  
  7. // 3  
  8. Protocol.registerProtocol("https", httpsProtocol);  
  9.  
  10. HttpClient client = new HttpClient();  
  11.  
  12. client.getState().setCredentials(  
  13.     new AuthScope("www.sample.com"80, AuthScope.ANY_REALM),  
  14.     new UsernamePasswordCredentials("username""password")  
  15. );  
  16.            
  17. // Request the protected resource via SSL  
  18. GetMethod get = new GetMethod("https://www.sample.com/protected.html");  
  19.  
  20. get.setDoAuthentication( true );  
  21.  
  22. try {  
  23.     int status = client.executeMethod( get );  
  24.  
  25.     // process the content from the response  
  26.     …  
  27. finally {  
  28.     get.releaseConnection();  

使用 Apache HttpClient 通過 Form-Based 認(rèn)證

Form-Based 認(rèn)證相對(duì) HTTP Basic 認(rèn)證而言過程較為復(fù)雜,需要開發(fā)者記錄下相關(guān)的 cookie 信息和部分 header 字段并多次向站點(diǎn)發(fā)出請(qǐng)求。它的大致原理如下:

注意:不同的應(yīng)用可能有不同的配置方式,開發(fā)者可以先在瀏覽器中手動(dòng)訪問受保護(hù)資源,獲取 login.jsp。進(jìn)行分析后即可獲知對(duì)應(yīng)的認(rèn)證服務(wù)資源 j_security_check 的位置以及對(duì)應(yīng)的用戶名與密碼在表單中的字段。

假定我們需要訪問的受保護(hù)資源為 http://www.sample.com/sampleApp/sample.rss。首先我們需要向此保護(hù)資源發(fā)出請(qǐng)求。而由 Form-Based 認(rèn)證原理一節(jié)中可知,J2EE 服務(wù)器會(huì)將此請(qǐng)求重定向至 login.jsp。如果仔細(xì)分析 login.jsp 我們能發(fā)現(xiàn)它僅僅是一個(gè) HTML 表單,其中有兩個(gè)字段 j_username 和 j_password 分別記錄用戶名和密碼,而提交的目標(biāo)則是 j_security_check。通常情況下,J2EE 構(gòu)架會(huì)在每個(gè)站點(diǎn)應(yīng)用的根節(jié)點(diǎn)定義一個(gè) j_security_check 的資源。而我們的站點(diǎn)的應(yīng)用程序根(Application Root)為 sampleApp。因而,通過將用戶名,密碼以及相關(guān) cookie 和 header 字段以 POST 方式發(fā)送至 http://www.sample.com/sampleApp/j_security_check 即可通過站點(diǎn)認(rèn)證。在通過站點(diǎn)認(rèn)證后,服務(wù)器端將給出一個(gè)新的重定向,通常它將指向了用戶最初試圖訪問的受保護(hù)資源(本例中也就是 http://www.sample.com/sampleApp/sample.rss)。我們只需要再次創(chuàng)建訪問對(duì)象向此資源發(fā)出請(qǐng)求即可獲得其內(nèi)容。

以下給出一個(gè)示例:

清單 3. Form-Based 認(rèn)證示例

  1.                   
  2. HttpClient client = new HttpClient();  
  3. client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);  
  4.  
  5. // 1  
  6. GetMethod authget = new GetMethod("httpwww.sample.comsampleAppsample.rss");  
  7. try {  
  8.     client.executeMethod(authget);  
  9. }  
  10. catch (HttpException httpe) {  
  11.     httpe.printStackTrace();  
  12. }  
  13. catch (IOException ioe) {  
  14.     ioe.printStackTrace();  
  15. }  
  16.  
  17. // 2  
  18. NameValuePair[] data = new NameValuePair[2];  
  19. data[0] = new NameValuePair("j_username", username);  
  20. data[1] = new NameValuePair("j_password", password);  
  21.  
  22. PostMethod authpost = new PostMethod("http://www.sample.com/sampleApp/j_security_check");  
  23. authpost.setRequestBody(data);  
  24.  
  25. // 3  
  26. Header hCookie = authget.getRequestHeader("Cookie");  
  27. Header hHost = authget.getRequestHeader("Host");  
  28. Header hUserAgent = authget.getRequestHeader("User-Agent");  
  29. if (hCookie == null || hHost == null || hUserAgent == null) {  
  30.     return null;  
  31. }  
  32.  
  33. authpost.setRequestHeader(hCookie);  
  34. authpost.setRequestHeader(hHost);  
  35. authpost.setRequestHeader(hUserAgent);  
  36.  
  37. authget.releaseConnection();  
  38.  
  39. try {  
  40.     client.executeMethod(authpost);  
  41.  
  42.     // 4  
  43.     Header header = authpost.getResponseHeader("location");  
  44.     if (header != null) {  
  45.         String newuri = header.getValue();   
  46.         GetMethod redirect = new GetMethod(newuri);  
  47.  
  48.         client.executeMethod(redirect);   
  49.         // process the content from the response  
  50.         redirect.releaseConnection();              
  51.     }  
  52. catch (HttpException httpe) {  
  53.     httpe.printStackTrace();  
  54.     return null;  
  55. catch (IOException ioe) {  
  56.     ioe.printStackTrace();  
  57.     return null;  
  58. }  
  59. authpost.releaseConnection(); 

其中各個(gè)步驟解釋如下:

  1. 使用 GET 方式請(qǐng)求 sample.rss。服務(wù)器收到連接后將在響應(yīng)中給出連接信息,HttpClient 在接收到響應(yīng)后會(huì)將其保存至 cookie 中。
  2. 準(zhǔn)備第二次對(duì) j_security_check 的連接,將用戶名和密碼填入新的 POST 請(qǐng)求的正文。
  3. 將 cookie 和部分 header 字段拷貝至新請(qǐng)求的報(bào)頭中,并發(fā)送請(qǐng)求。
  4. 從認(rèn)證成功的響應(yīng)中獲取重定向,并對(duì)重定向指向的資源發(fā)出請(qǐng)求,獲取并處理內(nèi)容。

小  結(jié)

隨著 Web 2.0 時(shí)代的到來,Web 站點(diǎn)的數(shù)據(jù)和內(nèi)容顯得愈加重要。而為了收集這些數(shù)據(jù),人們需要利用計(jì)算機(jī)本身的搜集能力,通過后臺(tái)請(qǐng)求,而不是瀏覽器交互的方式去獲取站點(diǎn)的數(shù)據(jù)。而商業(yè)站點(diǎn)中普遍存在的認(rèn)證/授權(quán)機(jī)制顯然成為了開發(fā)此類數(shù)據(jù)收集程序的一道屏障。Apache HttpClient 根據(jù)這些需求,提供了多種 HTTP 認(rèn)證機(jī)制的實(shí)現(xiàn)方案。開發(fā)人員也可以利用 HttpClient 強(qiáng)大的底層功能,設(shè)計(jì)特定方案以通過 J2EE 站點(diǎn)的認(rèn)證體系。

原文鏈接:http://www.ibm.com/developerworks/cn/java/j-lo-httpclient-j2ee/

【編輯推薦】

  1. wabacus 3.2已發(fā)布 J2EE快速開發(fā)框架
  2. J2EE總結(jié):Java命名與目錄接口JNDI
  3. 對(duì)于大型公司項(xiàng)目平臺(tái)選擇J2EE的三層認(rèn)識(shí)
  4. 關(guān)于學(xué)習(xí)J2EE框架的反思
  5. 簡(jiǎn)單介紹J2EE應(yīng)用的五種核心策略
責(zé)任編輯:林師授 來源: IBM
相關(guān)推薦

2009-06-18 15:54:57

J2EE下使用JNDI

2009-06-23 08:06:46

J2EE體系架構(gòu)J2EE模型J2EE設(shè)計(jì)模式

2009-06-10 14:10:23

J2EE學(xué)習(xí)J2EE是什么

2009-06-11 17:06:11

J2EE歷史Java EE概述

2009-06-10 13:37:06

J2EE可伸縮性J2EE靈活性J2EE維護(hù)

2009-06-23 16:48:26

J2EE常見問題J2EE平臺(tái)

2009-06-22 17:05:41

Java EEJava企業(yè)應(yīng)用

2009-06-22 16:21:02

J2EE線程

2009-06-18 16:13:14

J2EE開發(fā)

2009-06-23 08:12:48

J2EE調(diào)用存儲(chǔ)過程

2009-06-22 17:34:40

J2EE架構(gòu)

2009-06-11 17:07:49

WebsphereJ2EE應(yīng)用程序

2019-01-08 16:26:43

Java EEJ2EEJakarta EE

2009-06-23 16:50:24

2009-06-23 16:52:55

J2EE縮寫名詞

2009-06-25 13:22:00

J2EE常用Jar包

2009-06-10 13:30:32

J2EE四層模型客戶層Web層

2009-06-08 21:34:09

J2EEJ2SEJ2ME

2009-06-11 17:19:47

J2EE設(shè)計(jì)模式Template

2009-06-22 11:04:00

Jdbc存儲(chǔ)過程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)