4

我在嘗試使用Apache HttpClient Java庫對使用基於表單的身份驗證(例如,facebook.com)的網站進行身份驗證。
使用本網站的程序爲主要例子:http://www.elitejavacoder.com/2013/10/http-client-form-based-authentication.html,我能夠做到這一點 - 但有一些我不瞭解這個程序的事情。下面是代碼:使用HttpClient進行基於表單的身份驗證 - j_security_check

package com.elitejavacoder.http.client; 

import java.util.ArrayList; 
import java.util.List; 

import org.apache.http.HttpEntity; 
import org.apache.http.HttpHost; 
import org.apache.http.HttpResponse; 
import org.apache.http.NameValuePair; 
import org.apache.http.client.entity.UrlEncodedFormEntity; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.client.params.ClientPNames; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.message.BasicNameValuePair; 
import org.apache.http.util.EntityUtils; 

public class HttpClientFormAuthentication { 
    public static void main(String[] agrs) { 
     String host = "yourhostname.com"; 
     int port = 8080; 
     String protocol = "http"; 

     DefaultHttpClient client = new DefaultHttpClient(); 

     try { 
      HttpHost httpHost = new HttpHost(host, port, protocol); 
      client.getParams().setParameter(ClientPNames.DEFAULT_HOST, httpHost); 

      HttpGet securedResource = new HttpGet("/secured/index.jsp");    
      HttpResponse httpResponse = client.execute(securedResource); 
      HttpEntity responseEntity = httpResponse.getEntity(); 
      String strResponse = EntityUtils.toString(responseEntity); 
      int statusCode = httpResponse.getStatusLine().getStatusCode(); 
      EntityUtils.consume(responseEntity); 

      System.out.println("Http status code for Unauthenticated Request: " + statusCode);// Statue code should be 200 
      System.out.println("Response for Unauthenticated Request: \n" + strResponse); // Should be login page 
      System.out.println("================================================================\n"); 

      HttpPost authpost = new HttpPost("/j_security_check"); 
      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(); 
      nameValuePairs.add(new BasicNameValuePair("j_username", "yourusername")); 
      nameValuePairs.add(new BasicNameValuePair("j_password", "yourpassword")); 
      authpost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 

      httpResponse = client.execute(authpost); 
      responseEntity = httpResponse.getEntity(); 
      strResponse = EntityUtils.toString(responseEntity); 
      statusCode = httpResponse.getStatusLine().getStatusCode(); 
      EntityUtils.consume(responseEntity); 

      System.out.println("Http status code for Authenticattion Request: " + statusCode);// Status code should be 302 
      System.out.println("Response for Authenticattion Request: \n" + strResponse); // Should be blank string 
      System.out.println("================================================================\n"); 

      httpResponse = client.execute(securedResource); 
      responseEntity = httpResponse.getEntity(); 
      strResponse = EntityUtils.toString(responseEntity); 
      statusCode = httpResponse.getStatusLine().getStatusCode(); 
      EntityUtils.consume(responseEntity); 

      System.out.println("Http status code for Authenticated Request: " + statusCode);// Status code should be 200 
      System.out.println("Response for Authenticated Request: \n" + strResponse);// Should be actual page 
      System.out.println("================================================================\n"); 
     } 
     catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 

我有以下問題(行號我要指在我上面提供的,因爲StackOverflow上不允許包含行號的鏈接的情況下):

  • 「/ j_security_check」(第41行)究竟是什麼?作者如何知道他必須使用「j_security_check」而不是安全資源的名稱?

  • 怎麼樣,字符串「strResponse = EntityUtils.toString(responseEntity);」 (第49行),這是「httpResponse = client.execute(authpost);」之後的兩行(第47行)不同於字符串「strResponse = EntityUtils.toString(responseEntity);」 (第59行),這是「httpResponse = client.execute(securedResource)」之後的兩行; (第57行)?
    基本上,第47行和第57行之間的「客戶端」發生了什麼變化?

謝謝

回答

5

/j_security_check是一種表單操作,因此容器知道此請求用於身份驗證,容器處理該請求。 /j_security_check是用於提交特定於Enterprise Java應用程序服務器的身份驗證表單的網頁地址。

j_usernamej_password是提交用戶名和密碼的請求參數的名稱。這三個應該以這種方式命名(即j_security_check,j_usernamej_password),以便容器將該請求作爲認證請求處理,並且它可以從提交的請求中檢索所需的信息(即,用戶名和密碼)。

作者知道他/她需要使用/j_security_check,因爲他/她假設他正在對J2EE應用服務器進行身份驗證。這不是一個很好的假設。注意端口設置爲8080?這是Java服務器(如Tomcat)通常使用的端口,因此它們不會與HTTP服務器上的端口80發生衝突。

strResponse在第47行包含登錄請求本身的內容(它什麼都不是),第57行的strResponse包含受保護頁面的內容。這是故障:

如果您在網絡瀏覽器中這樣做,會發生以下情況。

  • 您將輸入受保護頁面的地址並按Enter鍵。
  • 由於您未通過身份驗證,因此服務器會以登錄表單頁面進行響應。
  • 您將輸入您的用戶名和密碼,然後單擊提交。
  • 你會得到你的安全頁面。服務器將返回一個302重定向代碼,其中包含您最初請求的地址以及您的瀏覽器將存儲的身份驗證Cookie。您的瀏覽器會重新訪問此頁面,但現在您的瀏覽器也會發送該Cookie,因此您不會看到登錄表單,而是顯示您嘗試訪問的頁面。

第31行是沒有驗證的初始頁面訪問。 第38-39行顯示登錄表單, 41-45行等同於將您的用戶名和密碼輸入到表單中。
第47行就像點擊提交按鈕。
第49行顯示了服務器發送迴應的內容。注意54行註釋是「應該是空白字符串」。當您提交用戶名和密碼時,您最關心的是HTTP狀態。打印出狀態碼的行中的註釋顯示「狀態碼應該是302」。 302是告訴瀏覽器重定向的HTTP狀態。響應標題將包含您的瀏覽器重定向到的地址。響應標頭還包含身份驗證cookie。如果打印出來也會很好,這將有助於理解這一切如何運作。該代碼手動執行第57行的重定向,但假設它將被重定向到它嘗試在第31行訪問的受保護頁面,而不是從HTTP響應頭部中檢索該地址。

client的最大改變是,第57行client具有認證cookie,類似於瀏覽器操作。 DefaultHttpClient在底層處理你所有的事情。

身份驗證cookie來自服務器,採用Set-Cookie HTTP標頭的形式。這告訴client存儲cookie。然後,在發出請求時,客戶端會發送Cookie HTTP標頭以及cookie數據。

client最初在包含它存儲的登錄表單的響應中接收cookie。當client發送填充表單時,該cookie也包含在請求中,並且此後每個請求都發送到服務器。因此,一旦您通過身份驗證,服務器就會存儲該信息並將其與Cookie相關聯。然後,當後續請求來自client時,服務器將看到cookie並記得您已經通過身份驗證。 client與瀏覽器做同樣的事情來管理cookie與服務器的數據傳輸。

+0

您知道您的答案几乎就是這樣的完美副本:https://www.quora .COM /如何-DO-I-利用形態基於使用的身份驗證 - - HttpClient的-通j_security_check –

0

的「/ j_security_check」是使用Spring框架來檢查用戶的憑據端點(你可以在這裏找到這些信息:http://docs.spring.io/spring-security/site/docs/3.2.4.RELEASE/reference/htmlsingle/#form-login-filter,默認的終點是「/ j_spring_security_check」)。

作者知道他/她必須使用這個URL,因爲他/她已經在Spring Framework的配置中設置了URL(它在元素中定義,設置URL以修改「login-processing- url「屬性)。

在第47行和第57行之間,客戶端已被重定向到另一個URL並檢索到該URL。客戶端應該重定向到的URL由「default-target-url」屬性定義。請注意,在登錄頁面顯示之前,Spring框架還可能會將用戶重定向到他/她所請求的URL。

+0

謝謝。但是在第47行和第57行之間的客戶端結構究竟發生了什麼樣的物理變化呢? 因爲如果我在57行之前(包括所有正確的主機,端口等)創建了一個新的'DefaultHttpClient'(稱爲'client 2')對象,並且調用了'httpResponse = client2。執行(securedResource);'使用'client2',第58行的結果實體和第59行的結果字符串將會不同於如果我用'client'調用所有這些方法。 執行第47行後,發生了「客戶端」問題,它使得您可以在第57行獲得受保護的資源。 – user224567893

相關問題