HttpClient 教程 (四)

第四章 HTTP認證

HttpClient提供對由HTTP標準規(guī)范定義的認證模式的完全支持缝其。HttpClient的認證框架可以擴展支持非標準的認證模式,比如NTLM和SPNEGO台囱。

4.1 用戶憑證

任何用戶身份驗證的過程都需要一組可以用于建立用戶身份的憑據(jù)。用戶憑證的最簡單的形式可以僅僅是用戶名/密碼對读整。UsernamePasswordCredentials代表了一組包含安全規(guī)則和明文密碼的憑據(jù)簿训。這個實現(xiàn)對由HTTP標準規(guī)范中定義的標準認證模式是足夠的

UsernamePasswordCredentials creds = new UsernamePasswordCredentials("user", "pwd");

System.out.println(creds.getUserPrincipal().getName());

System.out.println(creds.getPassword());

輸出內(nèi)容為:

user

pwd

NTCredentials是微軟Windows指定的實現(xiàn),它包含了除了用戶名/密碼對外米间,一組額外的Windows指定的屬性强品,比如用戶域名的名字,比如在微軟的Windows網(wǎng)絡中屈糊,相同的用戶使用不同設置的認證可以屬于不同的域的榛。

NTCredentials creds = new NTCredentials("user", "pwd", "workstation", "domain");

System.out.println(creds.getUserPrincipal().getName());

System.out.println(creds.getPassword());

輸出內(nèi)容為:

DOMAIN/user

pwd

4.2 認證模式

AuthScheme接口代表了抽象的,面向挑戰(zhàn)-響應的認證模式逻锐。一個認證模式期望支持如下的功能:

解析和處理由目標服務器在對受保護資源請求的響應中發(fā)回的挑戰(zhàn)夫晌。

提供處理挑戰(zhàn)的屬性:認證模式類型和它的參數(shù),如果可用昧诱,比如這個認證模型可應用的領(lǐng)域晓淀。

對給定的憑證組和HTTP請求對響應真實認證挑戰(zhàn)生成認證字符串。

要注意認證模式可能是有狀態(tài)的盏档,涉及一系列的挑戰(zhàn)-響應交流凶掰。HttpClient附帶了一些AuthScheme實現(xiàn):

Basic(基本):Basic認證模式定義在RFC 2617中。這個認證模式是不安全的蜈亩,因為憑據(jù)以明文形式傳送懦窘。盡管它不安全,如果用在和TLS/SSL加密的組合中稚配,Basic認證模式是完全夠用的畅涂。

Digest(摘要):Digest認證模式定義在RFC 2617中。Digest認證模式比Basic有顯著的安全提升道川,對不想通過TLS/SL加密在完全運輸安全上開銷的應用程序來說也是很好的選擇午衰。

NTLM:NTLM是一個由微軟開發(fā)的優(yōu)化Windows平臺的專有認證模式苹丸。NTLM被認為是比Digest更安全的模式。這個模式需要外部的NTLM引擎來工作苇经。要獲取更多詳情請參考包含在HttpClient發(fā)布包中的NTLM_SUPPORT.txt文檔赘理。

4.3 HTTP認證參數(shù)

有一些可以用于定制HTTP認證過程和獨立認證模式行為的參數(shù):

'http.protocol.handle-authentication':定義了是否認證應該被自動處理。這個參數(shù)期望的得到一個java.lang.Boolean類型的值扇单。如果這個參數(shù)沒有被設置商模,HttpClient將會自動處理認證。

'http.auth.credential-charset':定義了當編碼用戶憑證時使用的字符集蜘澜。這個參數(shù)期望得到一個java.lang.String類型的值施流。如果這個參數(shù)沒有被設置,那么就會使用US-ASCII鄙信。

4.4 認證模式注冊表

HttpClient使用AuthSchemeRegistry類維護一個可用的認證模式的注冊表瞪醋。對于每個默認的下面的模式是注冊過的:

Basic:基本認證模式

Digest:摘要認證模式

請注意NTLM模式?jīng)]有對每個默認的進行注冊。NTLM不能對每個默認開啟是應為許可和法律上的原因装诡。要獲取更詳細的關(guān)于如何開啟NTLM支持的內(nèi)容請看這部分银受。

4.5 憑據(jù)提供器

憑據(jù)提供器意來維護一組用戶憑據(jù),還有能夠?qū)μ囟ㄕJ證范圍生產(chǎn)用戶憑據(jù)鸦采。認證范圍包括主機名宾巍,端口號,領(lǐng)域名稱和認證模式名稱渔伯。當使用憑據(jù)提供器來注冊憑據(jù)時顶霞,我們可以提供一個通配符(任意主機,任意端口锣吼,任意領(lǐng)域选浑,任意模式)來替代確定的屬性值。如果直接匹配沒有發(fā)現(xiàn)玄叠,憑據(jù)提供器期望被用來發(fā)現(xiàn)最匹配的特定范圍古徒。

HttpClient可以和任意實現(xiàn)了CredentialsProvider接口的憑據(jù)提供器的物理代表一同工作。默認的CredentialsProvider實現(xiàn)被稱為BasicCredentialsProvider诸典,它是簡單的憑借java.util.HashMap的實現(xiàn)描函。

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")));

輸出內(nèi)容為:

[principal: u1]

[principal: u2]

null

[principal: u3]

4.6 HTTP認證和執(zhí)行上下文

HttpClient依賴于AuthState類來跟蹤關(guān)于認證過程狀態(tài)的詳細信息。在HTTP請求執(zhí)行過程中狐粱,HttpClient創(chuàng)建2個AuthState的實例:一個對于目標主機認證,另外一個對于代理認證胆数。如果目標服務器或代理需要用戶認證肌蜻,那么各自的AuthState實例將會被在認證處理過程中使用的AuthScope,AuthScheme和Crednetials來填充必尼。AuthState可以被檢查來找出請求的認證是什么類型的蒋搜,是否匹配AuthScheme的實現(xiàn)篡撵,是否憑據(jù)提供器對給定的認證范圍去找用戶憑據(jù)。

在HTTP請求執(zhí)行的過程中豆挽,HttpClient添加了下列和認證相關(guān)的對象到執(zhí)行上下文中:

'http.authscheme-registry':AuthSchemeRegistry實例代表真實的認證模式注冊表育谬。在本地內(nèi)容中設置的這個屬性的值優(yōu)先于默認的。

'http.auth.credentials-provider':CookieSpec實例代表了真實的憑據(jù)提供器帮哈。在本地內(nèi)容中設置的這個屬性的值優(yōu)先于默認的膛檀。

'http.auth.target-scope':AuthState實例代表了真實的目標認證狀態(tài)。在本地內(nèi)容中設置的這個屬性的值優(yōu)先于默認的娘侍。

'http.auth.proxy-scope':AuthState實例代表了真實的代理認證狀態(tài)咖刃。在本地內(nèi)容中設置的這個屬性的值優(yōu)先于默認的。

本地的HttpContext對象可以用于定制HTTP認證內(nèi)容憾筏,并先于請求執(zhí)行或在請求被執(zhí)行之后檢查它的狀態(tài):

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不支持開箱的搶占認證嚎杨,因為濫用或重用不正確的搶占認證可能會導致嚴重的安全問題,比如將用戶憑據(jù)以明文形式發(fā)送給未認證的第三方氧腰。因此枫浙,用戶期望評估搶占認證和在它們只能應用程序環(huán)境內(nèi)容安全風險潛在的好處,而且要求使用如協(xié)議攔截器的標準HttpClient擴展機制添加對搶占認證的支持古拴。

這是一個簡單的協(xié)議攔截器自脯,如果沒有企圖認證,來搶先引入BasicScheme的實例到執(zhí)行上下文中斤富。請注意攔截器必須在標準認證攔截器之前加入到協(xié)議處理鏈中膏潮。

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());

// 獲得匹配目標主機的憑據(jù)

Credentials creds = credsProvider.getCredentials(authScope);

// 如果發(fā)現(xiàn)了,搶先生成BasicScheme

if (creds != null) {

authState.setAuthScheme(new BasicScheme());

authState.setCredentials(creds);

}

}

}

};

DefaultHttpClient httpclient = new DefaultHttpClient();

// 作為第一個攔截器加入到協(xié)議鏈中

httpclient.addRequestInterceptor(preemptiveAuth, 0);

4.8 NTLM 認證

當前HttpClient沒有提對開箱的NTLM認證模式的支持也可能永遠也不會满力。這個原因是法律上的而不是技術(shù)上的焕参。然而,NTLM認證可以使用外部的NTLM引擎比如JCIFS[http://jcifs.samba.org/]來開啟油额,類庫由Samba[http://www.samba.org/]項目開發(fā)叠纷,作為它們Windows的交互操作程序套裝的一部分。要獲取詳細內(nèi)容請參考HttpClient發(fā)行包中包含的NTLM_SUPPORT.txt文檔潦嘶。

4.8.1 NTLM連接持久化

NTLM認證模式是在計算開銷方面昂貴的多的涩嚣,而且對標準的Basic和Digest模式的性能影響也很大。這很可能是為什么微軟選擇NTLM認證模式為有狀態(tài)的主要原因之一掂僵。也就是說航厚,一旦認證通過,用戶標識是和連接的整個生命周期相關(guān)聯(lián)的锰蓬。NTLM連接的狀態(tài)特性使得連接持久化非常復雜幔睬,對于明顯的原因,持久化NTLM連接不能被使用不同用戶標識的用戶重用芹扭。標準的連接管理器附帶HttpClient是完全能夠管理狀態(tài)連接的麻顶。而邏輯相關(guān)的赦抖,使用同一session和執(zhí)行上下文為了讓它們了解到當前的用戶標識的請求也是極為重要的。否則辅肾,HttpClient將會終止對每個基于NTLM保護資源的HTTP請求創(chuàng)建新的HTTP連接队萤。要獲取關(guān)于有狀態(tài)的HTTP連接的詳細討論,請參考這個部分矫钓。

因為NTLM連接是有狀態(tài)的要尔,通常建議使用相對簡單的方法觸發(fā)NTLM認證,比如GET或HEAD份汗,而重用相同的連接來執(zhí)行代價更大的方法盈电,特別是它們包含請求實體,比如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");

// 保證相同的內(nèi)容來用于執(zhí)行邏輯相關(guān)的請求

HttpContext localContext = new BasicHttpContext();

// 首先執(zhí)行簡便的方法匆帚。這會觸發(fā)NTLM認證

HttpGet httpget = new HttpGet("/ntlm-protected/info");

HttpResponse response1 = httpclient.execute(target, httpget, localContext);

HttpEntity entity1 = response1.getEntity();

if (entity1 != null) {

entity1.consumeContent();

}

//之后使用相同的內(nèi)容(和連接)執(zhí)行開銷大的方法。

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();

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旁钧,一起剝皮案震驚了整個濱河市吸重,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歪今,老刑警劉巖嚎幸,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異寄猩,居然都是意外死亡嫉晶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門田篇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來替废,“玉大人,你說我怎么就攤上這事泊柬∽盗停” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵兽赁,是天一觀的道長状答。 經(jīng)常有香客問我,道長刀崖,這世上最難降的妖魔是什么惊科? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蒲跨,結(jié)果婚禮上译断,老公的妹妹穿的比我還像新娘。我一直安慰自己或悲,他們只是感情好孙咪,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巡语,像睡著了一般翎蹈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上男公,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天荤堪,我揣著相機與錄音,去河邊找鬼枢赔。 笑死澄阳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的踏拜。 我是一名探鬼主播碎赢,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼速梗!你這毒婦竟也來了肮塞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤姻锁,失蹤者是張志新(化名)和其女友劉穎枕赵,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體位隶,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡拷窜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涧黄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篮昧。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弓熏,靈堂內(nèi)的尸體忽然破棺而出恋谭,到底是詐尸還是另有隱情,我是刑警寧澤挽鞠,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布疚颊,位于F島的核電站,受9級特大地震影響信认,放射性物質(zhì)發(fā)生泄漏材义。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一嫁赏、第九天 我趴在偏房一處隱蔽的房頂上張望其掂。 院中可真熱鬧,春花似錦潦蝇、人聲如沸款熬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贤牛。三九已至惋鹅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間殉簸,已是汗流浹背闰集。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留般卑,地道東北人武鲁。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像蝠检,于是被迫代替她去往敵國和親沐鼠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 今年的國慶沒有涌入人群中 待在家里看世界 剛好下個月同事搬新家 于是臨摹了一幅蘋果準備送她 寓意“平平安安” 希望...
    大雲(yún)DAYUN閱讀 374評論 0 1
  • 若想眾生相蝇率,即看本我相迟杂,洗不走俗塵,請洗掉你的基因本慕,不脫胎也不換骨排拷,只歸依心。
    深深是藍閱讀 213評論 1 4
  • 1 他:我家現(xiàn)在餛飩和茄餅都不放韭菜了锅尘。 她:為什么监氢? 他:因為,你不喜歡吃藤违。 2 他:以前喜歡得瑟浪腐,有點事就愛滿...
    林陌鹿閱讀 571評論 2 11