Java 使用 HttpClient 的基于表单的身份验证 - j_security_check
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24455484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Form-based Authentication using HttpClient - j_security_check
提问by user224567893
I'm trying to authenticate myself to a website that uses form-based authentication (e.g., facebook.com) using the Apache HttpClient Java library.
Using this website's program as a main example: http://www.elitejavacoder.com/2013/10/http-client-form-based-authentication.html, I was able to do it - but there are a few things that I'm not understanding about this program. Here is the code:
我正在尝试使用 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();
}
}
}
I have the following questions (the line numbers I'm going to refer to are in the context of the link that I provided above, since StackOverflow doesn't allow to include line numbers):
我有以下问题(我将要引用的行号在我上面提供的链接的上下文中,因为 StackOverflow 不允许包含行号):
What exactly is "/j_security_check" (line 41)? And how did the author knew that he had to use "j_security_check" instead of the name of the secured resource?
How come that the string "strResponse = EntityUtils.toString(responseEntity);" (line 49), which is two lines after "httpResponse = client.execute(authpost);" (line 47), is different from the string "strResponse = EntityUtils.toString(responseEntity);" (line 59), which is two lines after "httpResponse = client.execute(securedResource);" (line 57)?
Basically, what changes happen to "client" between lines 47 and 57?
“/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 行之间的“客户端”发生了什么变化?
Thank you
谢谢
采纳答案by user224567893
The /j_security_check
is a form action so that the container knows that this request is for authentication and the container handles that. /j_security_check
is a web page address for submitting authentication forms that is specific to Enterprise Java application servers.
这/j_security_check
是一个表单操作,以便容器知道此请求用于身份验证,并且容器会处理该请求。/j_security_check
是用于提交特定于 Enterprise Java 应用程序服务器的身份验证表单的网页地址。
j_username
and j_password
are names of the request parameters to submit both the username and password. These three should be named in such a way (i.e. j_security_check
, j_username
and j_password
) so that the container handles this request as an authentication request and it can retrieve the required information (i.e. username and password) from the submitted request.
j_username
和j_password
是提交用户名和密码的请求参数的名称。这三个应该以这样的方式命名(即j_security_check
,j_username
和j_password
),以便容器将此请求作为身份验证请求处理,并且可以从提交的请求中检索所需的信息(即用户名和密码)。
The author knew that he/she needed to used /j_security_check
because he/she is assuming that he is authenticating against a J2EE app server. This is not a great assumption. Notice that the port is set to 8080? That is the port typically used by Java servers like Tomcat so they don't collide with port 80 on an HTTP server.
作者知道他/她需要使用,/j_security_check
因为他/她假设他正在对 J2EE 应用服务器进行身份验证。这不是一个很好的假设。注意到端口设置为 8080 了吗?这是 Java 服务器(如 Tomcat)通常使用的端口,因此它们不会与 HTTP 服务器上的端口 80 发生冲突。
strResponse
at line 47 contains the content of the login request itself (which is nothing), and strResponse
at line 57 contains the content of the secured page. This is the breakdown:
strResponse
第 47 行包含登录请求本身的内容(什么都没有),strResponse
第 57 行包含受保护页面的内容。这是分解:
The following would happen if you were doing this in a web browser.
如果您在 Web 浏览器中执行此操作,则会发生以下情况。
- You would type in the address of the secured page and hit Enter.
- Since you're not authenticated, the server would respond with a login form page.
- You would type in your username and password and click Submit.
- You would get your secure page. The server would return a 302 redirect code with the address you originally requested, along with an authentication cookie, which your browser would store. Your browser re-accesses this page, but now your browser sends the cookie as well, so instead of giving you a login form, you get the page you were trying to access.
- 您将输入受保护页面的地址并按 Enter。
- 由于您未通过身份验证,服务器将使用登录表单页面进行响应。
- 您将输入您的用户名和密码,然后单击提交。
- 你会得到你的安全页面。服务器将返回一个带有您最初请求的地址的 302 重定向代码,以及您的浏览器将存储的身份验证 cookie。您的浏览器会重新访问此页面,但现在您的浏览器也发送了 cookie,因此您获得的不是登录表单,而是您尝试访问的页面。
Line 31 is the initial page access without authentication.
Lines 38-39 are displaying the login form,
Lines 41-45 are the equivalent of typing your username and password into a form.
Line 47 is like hitting the Submit button.
Line 49 is showing what the server sent in response. Notice in line 54 the comment is "Should be blank string". When you submit the username and password, what you are most concerned about in the response is the HTTP status. The comment in the line that prints out the status code says "Status code should be 302". 302 is the HTTP status which tells the browser to redirect. The response headers would contain an address for your browser to redirect to. The response headers also contain the authentication cookie. It would be nice if that were printed out too, it would help with understanding how this all works. The code is manually doing the redirect on line 57, but it is assuming that it will be redirected to the secured page it tried to access on line 31, rather than retrieving that address from the HTTP response headers.
第 31 行是未经身份验证的初始页面访问。第 38-39 行显示登录表单,第 41-45 行相当于在表单中输入您的用户名和密码。
第 47 行就像点击提交按钮。
第 49 行显示了服务器发送的响应内容。注意第 54 行的注释是“Should be blank string”。提交用户名和密码时,响应中最关心的是HTTP状态。打印出状态代码的行中的注释说“状态代码应该是 302”。302 是 HTTP 状态,它告诉浏览器重定向。响应标头将包含您的浏览器要重定向到的地址。响应头还包含身份验证 cookie。如果也打印出来就好了,这将有助于理解这一切是如何运作的。该代码在第 57 行手动执行重定向,但它假设它将被重定向到它在第 31 行尝试访问的安全页面,而不是从 HTTP 响应标头中检索该地址。
The biggest change to client
is that by line 57 client
has the authentication cookie, similar to the browser operation. DefaultHttpClient handles all that for you under the hood.
最大的变化client
是第57行client
有了认证cookie,类似于浏览器的操作。DefaultHttpClient 在幕后为您处理所有这些。
The authentication cookie comes from the server in the form of a Set-Cookie HTTP header. This tells the client
to store the cookie. Then, when making a request, the client sends a Cookie HTTP header, along with the cookie data.
身份验证 cookie 以 Set-Cookie HTTP 标头的形式来自服务器。这告诉client
存储cookie。然后,在发出请求时,客户端发送 Cookie HTTP 标头以及 cookie 数据。
The client
initially receives the cookie on the response that contains the login form, which it stores. When the client
sends back the filled-in form, that cookie is also included in the request, and every request to the server thereafter. So once you've authenticated, the server stores that information and associates it with the cookie. Then, when subsequent requests come from the client
, the server sees the cookie and remembers that you already authenticated. The client
does all the same things a browser does to manage cookie data transfer with the server.
在client
最初接收在包含登录表单,其存储响应该cookie。当client
发送回填写好的表单时,该 cookie 也包含在请求中,此后对服务器的每个请求都包含在内。因此,一旦您通过身份验证,服务器就会存储该信息并将其与 cookie 相关联。然后,当后续请求来自 时client
,服务器会看到 cookie 并记住您已通过身份验证。在client
完成所有浏览器确实给管理与服务器cookie数据传输同样的事情。
回答by Bartosz Mikulski
The "/j_security_check" is the endpoint used by Spring Framework to check user's credentials (you can find that information here: http://docs.spring.io/spring-security/site/docs/3.2.4.RELEASE/reference/htmlsingle/#form-login-filter, the default endpoint is "/j_spring_security_check").
“/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”)。
The author knew that he/she had to use this URL because he/she had set the URL in Spring Framework's configuration (it is defined in the element, to set the URL you have to modify the "login-processing-url" attribute).
作者知道他/她必须使用这个URL,因为他/她已经在Spring Framework的配置中设置了URL(它是在元素中定义的,要设置URL必须修改“login-processing-url”属性) .
Between lines 47 and 57 the client has been redirected to another URL and has retrieved that URL. The URL to which the client should be redirected is defined by the "default-target-url" attribute. Note that the Spring Framework may also redirect an user to the URL he/she requested before the login page has been displayed.
在第 47 行和第 57 行之间,客户端已被重定向到另一个 URL 并已检索到该 URL。客户端应重定向到的 URL 由“default-target-url”属性定义。请注意,Spring 框架还可能将用户重定向到他/她在显示登录页面之前请求的 URL。