The humble article uses the JMeter to test the Beijing PK10 platform Production (www.1159880099.com) QQ1159880099 with the CSRF token authentication Web API; In recent days, the project was not busy and practiced coding.
With the foundation of the previous JMeter script, basically the difficulty is in two places: Get the CSRF token, the transfer of the cookie.
Add dependencies First, and add the following in Pom.xml:
<!-- https:// mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.3</version> </dependency>
Explanatory effect:
HttpClient: Used to create httpClient, manage get and post methods, Get Request packet header, reply message content, management Cookiestore, etc.
- Jsoup: Used to parse the reply message and obtain the value of the CSRF token.
Create a Web API Test class:
public class Loginehr {
private final static String EHR_ADDRESS = "http://ourTestEHRServer:8083";static BasicCookieStore cookieStore = new BasicCookieStore();static CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
}
I chose the cookiestore way to manage the session; HttpClient now has another context to make the session persistent and to do further research later.
First write a method of the print reply message, do not do what processing, pure printing; Call or comment according to the actual need:
public class Loginehr {
private static void printResponse(HttpResponse httpResponse)
Throws ParseException, IOException {
Get Response message Entity
httpentity entity = httpresponse.getentity ();
Response status
System.out.println ("--------Status:" + httpresponse.getstatusline ());
System.out.println ("--------Headers:");
Headeriterator iterator = Httpresponse.headeriterator ();
while (Iterator.hasnext ()) {
System.out.println ("\ T" + iterator.next ());
}
Determine if the response entity is empty
if (Entity! = null) {
String responsestring = entityutils.tostring (entity);
System.out.println ("--------Response Length:" + responsestring.length ());
System.out.println ("--------Response content:"
- Responsestring.replace ("\ r \ n", ""));
}
}
}
Now write the test method, although the length is longer, still written in the main () method, easy to display:
public class Loginehr {
private final static String EHR_ADDRESS = "http://ourTestEHRServer:8083";static BasicCookieStore cookieStore = new BasicCookieStore();static CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();public static void main(String[] args) throws Exception { String username = "00022222"; String password = "abc123456"; HttpResponse httpResponse = null; try { HttpGet httpGet = new HttpGet(EHR_ADDRESS); httpResponse = httpClient.execute(httpGet); System.out.println("--------Cookie store for the 1st GET: " + cookieStore.getCookies()); // 唯一的作用是打印应答报文,没有任何处理;实际测试时,可以不执行
Printresponse (HttpResponse);
// 取出第一次请求时,服务器端返回的JSESSIONID; // 实际上此处只是取出JSESSIONID用作打印;cookieStore自动保存了本次会话的Cookie信息
List cookies = cookiestore.getcookies ();
String cookie = cookies.tostring ();
String SessionID = cookie.substring ("[[Version:0][name:jsessionid][value:". Length (),
Cookie.indexof ("][domain"));
System.out.println ("--------The current Jsessionid is:" + SessionID);
httpClient.close(); } catch (Exception ex) { ex.printStackTrace(); }}
private static void Printresponse (HttpResponse httpresponse)
Throws ParseException, IOException {...}
}
Based on the experience of the previous JMeter test script, a GET request is sent first, and the CSRF token and Jsessionid are obtained from the reply message.
Notice the lines I commented out print Jsessionid code, before I introduced Cookiestore, I was thinking of writing a new cookie myself and assigning it to a couple of requests later.
When you use Cookiestore, you do not need to encapsulate the cookie yourself and add it to the request header, which is done automatically. Not deleted is also for the time needed to print.
After the cookie has been confessed, it is the turn to process the CSRF token. If you print out the answer to the first get, we can see that the token format is rendered as follows:
Previously in the JMeter script, I added a regular expression extractor to extract the content of the _CSRF.
Now I'm going to use Jsoup to parse and return content with the following code:
private static String Getcsrftoken (Httpentity responseentity) throws ioexception{
Get Web page content, specify encoding
String Web = entityutils.tostring (responseentity, "utf-8");
Document doc= jsoup.parse (web);
Selector, select feature information
String token = Doc.select ("meta[name=_csrf]"). Get (0). attr ("content");
System.out.println ("--------The current CSRF token is:" + token);
return token;}
This method is called in Main ():
// 利用Jsoup从应答报文中读取CSRF Token
String token = Getcsrftoken (responseentity);
Then encapsulate the Post's request content:
// 获取到CSRF Token后,用Post方式登录 HttpPost httpPost = new HttpPost(EHR_ADDRESS); // 拼接Post的消息体 List<NameValuePair> nvps = new ArrayList<NameValuePair>(); nvps.add(new BasicNameValuePair("username", username)); nvps.add(new BasicNameValuePair("password", password)); nvps.add(new BasicNameValuePair("_csrf", token)); HttpEntity loginParams = new UrlEncodedFormEntity(nvps, "utf-8"); httpPost.setEntity(loginParams); // 第二次请求,带有CSRF Token httpResponse = httpClient.execute(httpPost);
System.out.println ("--------Cookie store for the POST:" + cookiestore.getcookies ());
Printresponse (HttpResponse);
And then... A little bit of an accident happened here:
As you can imagine, you should be able to jump to a page where the login succeeds or the validation fails, and when the Post method executes, the status code returned from the server is 302 and is redirected to another URL.
If left unchecked, the direct submission of the following business queries will not be successful, the result of execution is back to the login page.
I climbed the internet for a while, found that the question post to get 301, 302 of the people are also a few, indicating that the pit is still a lot of people caused trouble.
Simply put, if the server is redirected to a new address, we also have to follow the new address, or the server will assume that the request is not handled correctly, even if my subsequent request with a full set of authentication tokens and cookies will be intercepted outside the system.
With this understanding, what I need to do next is to deal with code:302; Add code as follows:
// 取POST方法返回的HTTP状态码;不出意外的话是302 int code = httpResponse.getStatusLine().getStatusCode(); if (code == 302) { Header header = httpResponse.getFirstHeader("location"); // 跳转的目标地址是在 HTTP-HEAD 中的 String newUri = header.getValue(); // 这就是跳转后的地址,再向这个地址发出新申请,以便得到跳转后的信息是啥。 // 实际打印出来的是接口服务地址,不包括IP Address部分 System.out.println("--------Redirect to new location: " + newUri); httpGet = new HttpGet(EHR_ADDRESS + newUri); httpResponse = httpClient.execute(httpGet);
Printresponse (HttpResponse);
}
The place to note here is the location content of the jump. In my case, the server gives just a word "/work", preferably add a printing step.
After confirming that it is not a complete URL, you need to complete the link and then make a httpget request.
After this httpget is executed, I can confirm that I am logged in successfully (or, again, sent back to the login page, of course I have succeeded here).
The next step is to submit a get for the business query to confirm the ability to perform business operations on the system:
// 请求一次绩效;确认登录成功 String queryUrl = EHR_ADDRESS + "/emp/performance/mt/query"; httpGet = new HttpGet(queryUrl); httpResponse = httpClient.execute(httpGet); System.out.println("--------Result of the Cardpunch Query: "); printResponse(httpResponse);
Finally, after confirming that the result of the query is correct, the entire script is completed, and only the last business query needs to be modified to generate additional test scripts.
The complete source code is as follows:
Package com.jason.apitest;
Import Org.apache.http.Header;
Import Org.apache.http.HeaderIterator;
Import org.apache.http.HttpEntity;
Import Org.apache.http.HttpResponse;
Import Org.apache.http.NameValuePair;
Import org.apache.http.ParseException;
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.impl.client.BasicCookieStore;
Import org.apache.http.impl.client.CloseableHttpClient;
Import org.apache.http.impl.client.HttpClients;
Import Org.apache.http.message.BasicNameValuePair;
Import Org.apache.http.protocol.HTTP;
Import Org.apache.http.util.EntityUtils;
Import Org.jsoup.Jsoup;
Import org.jsoup.nodes.Document;
Import java.io.IOException;
Import java.util.ArrayList;
Import java.util.List;
public class Loginehr {
private final static String EHR_ADDRESS = "http://ourTestEHRServer:8083";static BasicCookieStore cookieStore = new BasicCookieStore();static CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();public static void main(String[] args) throws Exception { String username = "00022222"; String password = "abc123456"; HttpResponse httpResponse = null; try { HttpGet httpGet = new HttpGet(EHR_ADDRESS); httpResponse = httpClient.execute(httpGet); System.out.println("--------Cookie store for the 1st GET: " + cookieStore.getCookies()); // 唯一的作用是打印应答报文,没有任何处理;实际测试时,可以不执行
Printresponse (HttpResponse);
// 取出第一次请求时,服务器端返回的JSESSIONID; // 实际上此处只是取出JSESSIONID用作打印;cookieStore自动保存了本次会话的Cookie信息
//List cookies = cookiestore.getcookies ();
//String cookie = cookies.tostring ();
//String SessionID = cookie.substring ("[[Version:0][name:jsessionid][value:". Length (),
//Cookie.indexof ("] [domain]);
//System.out.println ("--------The current Jsessionid is:" + SessionID);
// 利用Jsoup从应答报文中读取CSRF Token HttpEntity responseEntity = httpResponse.getEntity(); String token = getCsrfToken(responseEntity); // 获取到CSRF Token后,用Post方式登录 HttpPost httpPost = new HttpPost(EHR_ADDRESS); // 拼接Post的消息体 List<NameValuePair> nvps = new ArrayList<NameValuePair>(); nvps.add(new BasicNameValuePair("username", username)); nvps.add(new BasicNameValuePair("password", password)); nvps.add(new BasicNameValuePair("_csrf", token)); HttpEntity loginParams = new UrlEncodedFormEntity(nvps, "utf-8"); httpPost.setEntity(loginParams); // 第二次请求,带有CSRF Token httpResponse = httpClient.execute(httpPost);
System.out.println ("--------Cookie store for the POST:" + cookiestore.getcookies ());
Printresponse (HttpResponse);
// 取POST方法返回的HTTP状态码;不出意外的话是302 int code = httpResponse.getStatusLine().getStatusCode(); if (code == 302) { Header header = httpResponse.getFirstHeader("location"); // 跳转的目标地址是在 HTTP-HEAD 中的 String newUri = header.getValue(); // 这就是跳转后的地址,再向这个地址发出新申请,以便得到跳转后的信息是啥。 // 实际打印出来的是接口服务地址,不包括IP Address部分 System.out.println("--------Redirect to new location: " + newUri); httpGet = new HttpGet(EHR_ADDRESS + newUri); httpResponse = httpClient.execute(httpGet);
Printresponse (HttpResponse);
}
Request a performance; Confirm login Success String Queryurl = ehr_address + "/emp/performance/mt/query"; HttpGet = new HttpGet (Queryurl); HttpResponse = Httpclient.execute (HttpGet); System.out.println ("--------Result of the Cardpunch Query:"); Printresponse (HttpResponse); Httpclient.close (); } catch (Exception ex) {ex.printstacktrace (); }}private static void Printresponse (HttpResponse httpresponse) throws ParseException, IOException {//Get Response message Entity httpentity entity = httpresponse.getentity (); Response Status System.out.println ("--------Status:" + Httpresponse.getstatusline ()); System.out.println ("--------Headers:"); Headeriterator iterator = Httpresponse.headeriterator (); while (Iterator.hasnext ()) {System.out.println ("\ T" + iterator.next ()); }//Determine if the response entity is empty if (entity! = null) {String responsestring = entityutils.tostring (entity); System.out.println ("--------Response Length:" + RESPONSESTRING.LEngth ()); System.out.println ("--------Response content:" + responsestring.replace ("\ r \ n", "")); }}private static string Getcsrftoken (Httpentity responseentity) throws ioexception{//Get Web page content, specify encoded String web = Entit Yutils.tostring (responseentity, "utf-8"); Document doc= jsoup.parse (web); Selector, select the feature information String token = Doc.select ("meta[name=_csrf]"). Get (0). attr ("content"); System.out.println ("--------The current CSRF token is:" + token); return token;}
}
Creating a Web API for testing CSRF token validation Using the Java encoding Beijing PK10 platform