【问题标题】:Form-based Authentication using HttpClient - j_security_check使用 HttpClient 的基于表单的身份验证 - j_security_check
【发布时间】:2014-08-18 18:42:56
【问题描述】:

我正在尝试使用 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 不允许包含行号):

  • 究竟什么是“/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 行之间的“客户端”发生了哪些变化?

谢谢

【问题讨论】:

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


    【解决方案1】:

    /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 行的注释是“应该是空白字符串”。当您提交用户名和密码时,您在响应中最关心的是 HTTP 状态。打印出状态代码的行中的注释说“状态代码应该是 302”。 302 是告诉浏览器重定向的 HTTP 状态。响应标头将包含您的浏览器重定向到的地址。响应标头还包含身份验证 cookie。如果也能打印出来就好了,这将有助于理解这一切是如何工作的。该代码在第 57 行手动执行重定向,但它假设它将被重定向到它在第 31 行尝试访问的安全页面,而不是从 HTTP 响应标头中检索该地址。

    client 最大的变化是在第 57 行 client 有认证 cookie,类似于浏览器的操作。 DefaultHttpClient 在后台为您处理所有这些。

    身份验证 cookie 以 Set-Cookie HTTP 标头的形式来自服务器。这告诉client 存储cookie。然后,当发出请求时,客户端会发送一个 Cookie HTTP 标头以及 cookie 数据。

    client 最初在包含登录表单的响应中接收 cookie,并存储该 cookie。当client 发回填写好的表单时,该 cookie 也包含在请求中,以及此后对服务器的每个请求。因此,一旦您进行了身份验证,服务器就会存储该信息并将其与 cookie 相关联。然后,当后续请求来自client 时,服务器会看到 cookie 并记住您已经通过身份验证。 client 与浏览器在管理与服务器的 cookie 数据传输时所做的所有事情相同。

    【讨论】:

    • 你知道你的答案几乎是这个的完美副本:quora.com/…
    【解决方案2】:

    “/j_security_check”是 Spring Framework 用于检查用户凭据的端点(您可以在此处找到该信息: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。

    【讨论】:

    • 谢谢。但是在第 47 行和第 57 行之间,client 的结构究竟发生了哪些物理变化?因为如果我在第 57 行之前创建了一个新的DefaultHttpClient(比如client 2)对象(包含所有正确的主机、端口等),并使用client2 调用httpResponse = client2.execute(securedResource);,则第58 行的结果实体和第 59 行的结果字符串与我使用 client 调用所有这些方法时不同。在执行第 47 行后,client 发生了一些事情,这样您就可以在第 57 行中获得受保护的资源。
    猜你喜欢
    • 2013-04-15
    • 2018-10-01
    • 2014-12-13
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 2015-02-06
    • 2012-06-06
    相关资源
    最近更新 更多