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

相关问题