使用HttpClient进行基于表单的身份验证 - j_security_check

时间:2014-06-27 15:27:14

标签: java apache-httpclient-4.x form-authentication j-security-check

我尝试使用Apache HttpClient Java库对使用基于表单的身份验证(例如,facebook.com)的网站进行身份验证。
使用这个网站的程序作为一个主要的例子:http://www.elitejavacoder.com/2013/10/http-client-form-based-authentication.html,我能够做到 - 但有一些事情我不理解这个程序。这是代码:

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不允许包含行号):

  • 究竟是什么&#34; / j_security_check&#34; (第41行)?那作者怎么知道他必须使用&#34; j_security_check&#34;而不是安全资源的名称?

  • 为什么字符串&#34; strResponse = EntityUtils.toString(responseEntity);&#34; (第49行),这是&#34之后的两行; httpResponse = client.execute(authpost);&#34; (第47行),不同于字符串&#34; strResponse = EntityUtils.toString(responseEntity);&#34; (第59行),这是&#34之后的两行; httpResponse = client.execute(securedResource);&#34; (第57行)?
    基本上,&#34;客户&#34;会发生什么变化?第47和57行之间?

谢谢

2 个答案:

答案 0 :(得分:7)

/j_security_check是表单操作,以便容器知道此请求用于身份验证,容器处理该请求。 /j_security_check是用于提交特定于Enterprise Java应用程序服务器的身份验证表单的网页地址。

j_usernamej_password是要提交用户名和密码的请求参数的名称。这三个应该以这样的方式命名(即j_security_checkj_usernamej_password),以便容器将此请求作为身份验证请求处理,并且它可以检索所需的信息(即用户名)来自提交的请求的密码)。

作者知道他/她需要使用/j_security_check,因为他/她假设他正在对J2EE应用服务器进行身份验证。这不是一个很好的假设。请注意,端口设置为8080?这是Tomcat等Java服务器通常使用的端口,因此它们不会与HTTP服务器上的端口80发生冲突。

第47行的

strResponse包含登录请求本身的内容(没有任何内容),第57行的strResponse包含受保护页面的内容。这是细分:

如果您在网络浏览器中执行此操作,则会发生以下情况。

  • 您可以输入受保护页面的地址,然后按Enter键。
  • 由于您未经过身份验证,服务器将使用登录表单页面进行响应。
  • 您可以输入用户名和密码,然后点击提交。
  • 您将获得安全页面。服务器将返回302重定向代码以及您最初请求的地址,以及您的浏览器将存储的身份验证cookie。您的浏览器重新访问此页面,但现在您的浏览器也会发送cookie,因此您无需提供登录表单,而是获得您尝试访问的页面。

第31行是没有身份验证的初始页面访问。 第38-39行显示登录表单, 第41-45行相当于在表单中输入您的用户名和密码 第47行就像点击提交按钮一样 第49行显示了服务器响应发送的内容。请注意第54行中的注释是&#34;应为空字符串&#34;。提交用户名和密码时,响应中最关心的是HTTP状态。打印出状态代码的行中的注释表示&#34;状态代码应为302&#34;。 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数据传输所做的所有事情。

答案 1 :(得分:0)

&#34; / j_security_check&#34;是Spring Framework用于检查用户凭据的端点(您可以在此处找到该信息:http://docs.spring.io/spring-security/site/docs/3.2.4.RELEASE/reference/htmlsingle/#form-login-filter,默认端点是&#34; / j_spring_security_check&#34;)。

作者知道他/她必须使用此URL,因为他/她已在Spring Framework的配置中设置了URL(它在元素中定义,设置您必须修改&#的URL) 34; login-processing-url&#34;属性)。

在第47行和第57行之间,客户端已被重定向到另一个URL并检索到该URL。应将客户端重定向到的URL由&#34; default-target-url&#34;定义。属性。请注意,Spring Framework还可能会在显示登录页面之前将用户重定向到他/她请求的URL。