NỘI DUNG BÀI HỌC
✳️ Sử dụng Basic Authentication trong REST Assured
✳️ Sử dụng Direst Authentication trong REST Assured
✳️ Sử dụng Form Authentication trong REST Assured
✳️ Sử dụng 0Auth Authentication trong REST Assured
✳️ Sử dụng Token để xác thực trong REST Assured
✳️ Sử dụng PUT method
✅ Tại sao cần xử lý xác thực trong test API automation
Chúng ta cần xử lý xác thực trong test API automation là để đáp ứng khâu xác thực của hệ thống trước khi truy cập vào một Endpoint cụ thể giống như cách mà chúng ta kiểm thử API thủ công hoặc kiểm thử trên UI nó cũng cần có bước xác thực thông qua Login với username password hoặc là điền form hiện lên từ website để nhập authentication chẳng hạn.
Và các loại Authentication thì chắc hẳn các bạn khi kiểm thử thủ công cũng biết rồi, chúng ta có vài loại xác thực chính thường gặp thôi chứ cũng không nhiều.
Sau đây An sẽ hướng dẫn các bạn cách xử lý từng loại xác thực trong Test Automation API với REST Assured nhé !!
✅ Sử dụng Basic Authentication trong REST Assured
Basic Authentication là loại xác thực cơ bản, yêu cầu người dùng gửi id người dùng và mật khẩu đã được mã hóa dưới dạng Base64. Nghĩa là thông tin bình thường nhất như "anhtester" và "Demo@123"
REST Assured cung cấp một cách dễ dàng để cấu hình thông tin xác thực trước khi gửi request với những hàm xây dựng sẵn tiện lợi.
Giả sử trước khi xác thực thì kết quả như này:
@Test
public void getData() {
RequestSpecification httpRequest = given();
Response response = httpRequest.get("https://postman-echo.com/basic-auth");
System.out.println("Data from the GET API: ");
System.out.println(response.getStatusCode());
System.out.println(response.getBody().asString());
}
Kết quả:
Data from the GET API:
401
Unauthorized
Kết quả trả về là mã code 401 và một thông báo "Unauthorized" nghĩa là không có quyền truy cập vào endpoint.
Giờ chúng ta dùng hàm hỗ trợ sẵn trong REST Assured để xác thực dạng cơ bản nhé:
@Test
public void testBasicAuth() {
RequestSpecification httpRequest = given().auth().basic("postman", "password");
Response response = httpRequest.get("https://postman-echo.com/basic-auth");
System.out.println("Data from the GET API: ");
System.out.println(response.getStatusCode());
System.out.println(response.getBody().asString());
}
Cụ thể là chúng ta dùng hàm auth().basic()
sau hàm given()
chổ khai báo Request nhé.
Kết quả sau khi xác thực:
Data from the GET API:
200
{
"authenticated": true
}
Ok hen, chắc chỉ vậy là đủ hiểu rồi, quá dễ dàng để xử lý vì có sẵn hết các hàm từ Rest Assured. Các loại authen khác cũng sẽ có hàm sẵn tương tự vậy 😋
🔆 Sử dụng hàm preemptive() để xác thực cơ bản
Cách khác để xác thực kiểu basic dễ dàng hơn là dùng hàm preemptive() nếu Dev thiết kế theo kiểu đòi hỏi thông tin dạng này.
@Test
public void testPreemptiveBasicAuth() {
RequestSpecification httpRequest = given().auth().preemptive().basic("postman", "password");
Response response = httpRequest.get("https://postman-echo.com/basic-auth");
System.out.println("Data from the GET API: ");
System.out.println(response.getStatusCode());
System.out.println(response.getBody().asString());
}
✅ Sử dụng Direst Authentication trong REST Assured
Digest Authentication là kiểu xác thực truy cập thông báo, là một trong những phương pháp đã được thống nhất mà máy chủ web có thể sử dụng để thương lượng thông tin xác thực, chẳng hạn như tên người dùng hoặc mật khẩu, với trình duyệt web của người dùng. Điều này có thể được sử dụng để xác nhận danh tính của người dùng trước khi gửi thông tin nhạy cảm, chẳng hạn như lịch sử giao dịch ngân hàng trực tuyến.
Nó áp dụng hàm băm cho tên người dùng và mật khẩu trước khi gửi chúng qua mạng. Ngược lại, xác thực truy cập cơ bản sử dụng mã hóa Base64 có thể đảo ngược dễ dàng thay vì băm, khiến nó không an toàn trừ khi được sử dụng cùng với TLS.
Về mặt kỹ thuật, xác thực thông báo là một ứng dụng băm mật mã MD5 để ngăn chặn các cuộc tấn công lặp lại. Nó sử dụng giao thức HTTP.
Kiểu xác thực Direct này cũng giống như Basic nhưng khác chổ kiểu mã hoá nó là dạng dùng hàm băm thông tin username và password.
Kiểu xác thực Digest được Rest Assured chuẩn bị sẵn hàm xử lý luôn rồi
@Test
public void testDigestAuth() {
RequestSpecification httpRequest = RestAssured.given().auth().digest("postman", "password");
Response response = httpRequest.get("https://postman-echo.com/basic-auth");
System.out.println("Data from the GET API: ");
System.out.println(response.getStatusCode());
System.out.println(response.getBody().asString());
}
✅ Sử dụng Form Authentication trong REST Assured
Form Authentication là xác thực dạng form điền thông tin được hiển thị ra từ hệ thống khi truy cập vào trước khi làm thao tác gì đó.
Dạng trên khác với trang Login bình thường nhen 😄
Các bạn vào trang này thử https://the-internet.herokuapp.com/basic_auth
Các xử lý xác thực dạng Form:
@Test
public void testFormAuth() {
given()
.auth()
.form("value1", "value2")
.get("your end point URL");
}
Thường giá trị là username và password hoặc thêm field gì đó nữa kèm theo chẳng hạn. Hệ thống yêu cầu gì thì chúng ta điền nấy thôi.
✅ Sử dụng OAuth Authentication trong REST Assured
OAuth Authentication là xác thực bên thứ 3, giống như kiểu dùng tài khoản Google để đăng nhập vào hệ thống hay tài khoản Microsoft, GitHub chẳng hạn.
Ví dụ nhìn phát hiểu ngay 😄
Xác thực dạng OAuth có 2 dạng là 0Auth1 và OAuth2. Trong lĩnh vực bảo mật API và cho phép quyền truy cập có kiểm soát vào tài nguyên người dùng, OAuth1 và OAuth2 đóng vai trò là những người chơi nổi bật. Mặc dù có chung mục đích cơ bản nhưng hai giao thức này khác nhau về cách tiếp cận và cơ chế.
🔆 Xác thực dạng OAuth1
OAuth1, thường được gọi đơn giản là OAuth, là phiên bản cũ hơn của giao thức OAuth tập trung vào việc cấp cho các ứng dụng của bên thứ ba quyền truy cập hạn chế vào tài nguyên người dùng trên các dịch vụ trực tuyến khác nhau. Nó được thiết kế để cho phép truy cập an toàn vào tài nguyên mà không cần chia sẻ thông tin xác thực thực tế của người dùng (tên người dùng và mật khẩu) với ứng dụng của bên thứ ba.
Xác thực OAuth1 bao gồm ba bên chính: người dùng (chủ sở hữu tài nguyên), ứng dụng khách (người tiêu dùng) và máy chủ tài nguyên (nhà cung cấp dịch vụ).
Cách xử lý xác thực OAuth1 trong Rest Assured nè:
@Test
public void testOAuth1() {
given()
.auth()
.oauth("consumerKey", "consumerSecret", "accessToken", "tokenSecret")
.get("your end point URL");
}
4 cái tham số đó lúc nào cũng sẽ được cung cấp đầy đủ nên các bạn yên tâm, anh bạn Dev sẽ cung cấp cho chúng ta hoặc một thư viện hệ thống nào đó sẽ có trang Docs hướng dẫn dùng API với kiểu xác thực OAuth1.
🔆 Xác thực dạng OAuth2
Ngược lại với người tiền nhiệm OAuth1 thì OAuth2 tự hào có cách tiếp cận hợp lý hơn và lấy người dùng làm trung tâm. Thay vì đi sâu vào sự phức tạp của việc tạo chữ ký, OAuth2 nhấn mạnh vào xác thực dựa trên mã thông báo. Cách tiếp cận này ưu tiên cả tính bảo mật và thân thiện với người dùng.
Hãy tưởng tượng một tình huống trong đó người dùng muốn cấp cho ứng dụng quyền truy cập vào tài nguyên của họ. OAuth2 phối hợp một điệu nhảy giữa ba người chơi chính: người dùng, ứng dụng và máy chủ ủy quyền. Thông qua bước nhảy này, ứng dụng sẽ nhận được mã thông báo truy cập—một khóa khó hiểu (à nó là Access Token ý mà), có thời gian tồn tại ngắn.
Mã thông báo này giống như phiếu cấp phép kỹ thuật số, cấp cho ứng dụng quyền truy cập có giới hạn vào tài nguyên của người dùng mà không tiết lộ thông tin xác thực nhạy cảm.
Nói vậy các bạn hiểu chưa ta, nó là cái Access Token được sinh tự động khi setting các quyền hạn xong nhấn Submit hoặc Generate cái nó phi ra một mã dài ngoằn chắc không ai nhớ đâu, nên note lại đâu đó 😝
https://github.com/settings/tokens/new
Ví dụ trên là mã Access Token cấp quyền truy cập vào hệ thống GitHub của cá nhân người dùng, dùng để bắt Trigger event chạy CI chẳng hạn. Sau đó chỉ cần copy mã Access Token dán vào là xong.
Cách xử lý xác thực OAuth2 trong Rest Assured nè:
@Test
public void testOAuth2() {
given()
.auth()
.oauth2("Access token")
.get("your end point URL");
}
✅ Sử dụng Token để xác thực trong REST Assured
Cách mà chúng ta thường dùng để xác thực quyền hạn vào hệ thống bình thường là sử dụng mã Access Token sau khi Login thành công để dùng nó truy cập vào các Endpoint API khác nhau. Này gọi là Authorization nè.
🔆 Thông tin thêm:
Authentication có nghĩa là xác minh danh tính của người dùng hoặc ứng dụng đang cố truy cập API. Về cơ bản nó cố gắng trả lời câu hỏi “Bạn là ai?”.
Các phương thức xác thực phổ biến bao gồm Basic Auth, Digest Auth, OAUTH, API Key, mã thông báo Bearer, v.v. Xác thực phù hợp đảm bảo rằng chỉ những người dùng hợp pháp mới có được quyền truy cập.
Authorization thường xảy ra sau khi xác thực (Authentication) và là quá trình cấp hoặc từ chối quyền truy cập dựa trên quyền của người dùng hoặc ứng dụng. Về cơ bản nó trả lời câu hỏi “Bạn được phép làm gì?”.
Authorization ngăn người dùng trái phép truy cập dữ liệu nhạy cảm hoặc thực hiện các hành động bị hạn chế. Ví dụ: cố gắng truy cập dữ liệu quản trị bằng thông tin xác thực của người dùng thông thường sẽ dẫn đến trạng thái trái phép.
🔆 Mã trạng thái HTTP 401 và 403
Khi xử lý xác thực và ủy quyền, bạn sẽ thường gặp hai mã trạng thái HTTP là 401 không được phép và 403 bị cấm.
- 401 trái phép: Mã này biểu thị rằng máy khách thiếu thông tin xác thực hợp lệ. Nói cách khác, khách hàng cần cung cấp thông tin xác thực hợp lệ để tiếp tục.
- 403 bị cấm: Mã 403 cho biết thông tin xác thực của khách hàng là hợp lệ nhưng họ không có các quyền cần thiết để truy cập tài nguyên được yêu cầu. Đó là sự từ chối truy cập do thiếu quyền hạn.
🔆 Cách để có được Token
Thường sau khi chúng ta Login thành công sẽ có Token sinh ra trong phiên đăng nhập đó, có thời gian và quyền hạn kèm theo.Ví dụ như hàm Login User của chúng ta học buổi trước:
@Test
public void testLoginUser() {
RequestSpecification request = given();
request.baseUri("https://api.anhtester.com/api")
.accept("application/json")
.contentType("application/json")
.body("{\n" +
" \"username\": \"anhtester\",\n" +
" \"password\": \"Demo@123\"\n" +
"}");
//Thực hiện phương thức post() để gửi dữ liệu đi
Response response = request.when().post("/login");
response.prettyPrint();
response.then().statusCode(200);
}
Kết quả:
{
"token": "2563|Q4UWVq6jYFFwF2AcWavNaMuKywPQzaszdWC8jQeca5d7ae2b"
}
Sau đó chúng ta dùng mã này để truy cập tiếp các Endpoint còn lại mà có yêu cầu Token. Ví dụ như api Edit User chẳng hạn:
https://api.anhtester.com/swagger/index.html#/User%20Management/updateUser
Hệ thống buộc chúng ta xác thực trước khi sử dụng api endpoint này
🔆 Các dùng Token dạng Cookie trong Rest Assured
@Test
public void testUseToken_Cookie() {
RequestSpecification request = given();
request.baseUri("https://restful-booker.herokuapp.com")
.contentType("application/json")
.accept("application/json")
.header("Cookie", "token=abc123")
.body("");
Response response = request.put("/booking/1");
}
🔆 Các dùng Token dạng Bearer trong Rest Assured
@Test
public void testUseToken_Bearer() {
//Cái token này sau khi Login sẽ thấy
// {
// "token": "2563|Q4UWVq6jYFFwF2AcWavNaMuKywPQzaszdWC8jQeca5d7ae2b"
// }
String accessToken = "2563|Q4UWVq6jYFFwF2AcWavNaMuKywPQzaszdWC8jQeca5d7ae2b";
RequestSpecification request = given();
request.baseUri("https://api.anhtester.com/api")
.contentType("application/json")
.accept("application/json")
.header("Authorization", "Bearer " + accessToken)
.body("");
Response response = request.put("/user/1");
}
Các bạn xem ví dụ dùng phương thức PUT để Edit User và Update Book là chúng ta hiểu hơn về việc dùng Token là như thế nào nhé.
✅ Sử dụng PUT method
Để sử dụng phương thức PUT
trong test API thì chúng ta dùng hàm put() giống như hàm post() bài trước.
Ví dụ edit User nhé:
@Test
public void testEditUser_NoAuth() {
//Chuẩn bị data
RegisterUserPOJO registerUserPOJO = new RegisterUserPOJO();
registerUserPOJO.setUsername("myduyen3");
registerUserPOJO.setPassword("Demo@123");
registerUserPOJO.setFirstName("Lê Thị");
registerUserPOJO.setLastName("Mỹ Duyên");
registerUserPOJO.setEmail("myduyen3@email.com");
registerUserPOJO.setPhone("0123456789");
registerUserPOJO.setUserStatus(1);
Gson gson = new Gson();
RequestSpecification request = given();
request.baseUri("https://api.anhtester.com/api")
.accept("application/json")
.contentType("application/json")
.body(gson.toJson(registerUserPOJO));
Response response = request.when().put("/user/2");
response.prettyPrint();
response.then().statusCode(200);
String message = response.getBody().path("message");
Assert.assertEquals(message, "Success", "The message not match.");
}
Chú ý chổ hàm request.when().put("/user/2") đơn giản dùng hàm put() thôi.
Nhưng vấn đề nó nằm ở chổ kết quả nè:
{
"message": "Unauthenticated."
}
java.lang.AssertionError: 1 expectation failed.
Expected status code <200> but was <401>.
Như nói ở trên, chúng ta cần có Token cho api edit này.
🔆 Lấy Token từ api Login
Chúng ta dùng ghi chú @BeforeMethod cho hàm "loginUser" để nó mặc định chạy trước mỗi hàm có @Test khi thực thi.
Giá trị token được lưu vào biến toàn cục TOKEN để sử dụng lại.
//Khai báo biến toàn tục TOKEN để lưu trữ từ hàm Login
String TOKEN = "";
@BeforeMethod
public void loginUser() {
//Khởi tạo giá trị cho các fields thông qua hàm xây dựng
LoginPOJO loginPOJO = new LoginPOJO("anhtester", "Demo@123");
//Dùng thư viện Gson để chuyển class POJO về dạng JSON
Gson gson = new Gson();
RequestSpecification request = given();
request.baseUri("https://api.anhtester.com/api")
.accept("application/json")
.contentType("application/json")
.body(gson.toJson(loginPOJO));
Response response = request.when().post("/login");
response.prettyPrint();
response.then().statusCode(200);
//Lưu giá trị token vào biến TOKEN nhé
TOKEN = response.getBody().path("token");
System.out.println(TOKEN);
}
🔆 Truyền Token vào api Edit User
@Test
public void testEditUser_HasAuth() {
//Chuẩn bị data cho edit user
RegisterUserPOJO registerUserPOJO = new RegisterUserPOJO();
registerUserPOJO.setUsername("myduyen4");
registerUserPOJO.setPassword("Demo@123");
registerUserPOJO.setFirstName("Lê Thị");
registerUserPOJO.setLastName("Mỹ Duyên");
registerUserPOJO.setEmail("myduyen4@email.com");
registerUserPOJO.setPhone("0123456789");
registerUserPOJO.setUserStatus(1);
Gson gson = new Gson();
RequestSpecification request = given();
request.baseUri("https://api.anhtester.com/api")
.accept("application/json")
.contentType("application/json")
.header("Authorization", "Bearer " + TOKEN)
.body(gson.toJson(registerUserPOJO));
Response response = request.when().put("/user/2");
response.prettyPrint();
response.then().statusCode(200);
String message = response.getBody().path("message");
Assert.assertEquals(message, "Success", "The message not match.");
}
Kết quả:
{
"token": "2572|reEzbkzNqrx6gyiT61tc1wIApOmjtXpsKIxMiJQT3807c7e6"
}
2572|reEzbkzNqrx6gyiT61tc1wIApOmjtXpsKIxMiJQT3807c7e6
{
"message": "Success",
"response": {
"id": 2,
"username": "myduyen4",
"firstName": "Lê Thị",
"lastName": "Mỹ Duyên",
"email": "myduyen4@email.com",
"phone": "0123456789",
"userStatus": 1
}
}
===============================================
Default Suite
Total tests run: 1, Passes: 1, Failures: 0, Skips: 0
===============================================
Như vậy là hàm loginUser đã chạy trước và đã lấy được giá trị Token thành công. Tiếp theo đó truyền vào hàm edit user thông qua kiểu xác thực Bearer để thực hiện phương thức PUT thành công.