JSON Web Token i jego obsługa w RestAssured
JWT, czyli JSON Web Token, to kompaktowy i samowystarczalny sposób bezpiecznego przesyłania informacji między dwiema stronami. Jest często używany do uwierzytelniania i autoryzacji w aplikacjach internetowych, interfejsach API i systemach rozproszonych. Mówiąc prościej, jest niczym cyfrowy paszport lub dowód osobisty, który zawiera zakodowane informacje o użytkowniku lub encji.
Wprowadzenie do JWT
JWT składa się z trzech części: nagłówka, zawartości i podpisu. Nagłówek określa typ tokena (którym jest JWT) i algorytm użyty do jego podpisania. Zawartość to rzeczywiste dane lub stwierdzenia („claims”), które mogą zawierać informacje, takie jak identyfikator użytkownika, rola, uprawnienia i inne istotne szczegóły. Stwierdzenia te zakodowano jako obiekt JSON.
Aby zapewnić integralność i autentyczność tokena, podpis generuje się przez połączenie nagłówka, zawartości i tajnego klucza znanego tylko serwerowi. Jest on dodawany do tokena, dzięki czemu odznacza się odpornością na manipulacje. Gdy serwer odbierze token, może zweryfikować podpis przy użyciu tego samego tajnego klucza i upewnić się, że token nie został zmodyfikowany lub naruszony.
Przykład
Nagłówek („Header”):
{
"alg": "HS256",
"typ": "JWT"
}
Zawartość („Payload”):
{
"name": "admin",
"age": 35
}
Podpis („Signature”):
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
my_secret
)
Zakodowana postać tokena JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiYWRtaW4iLCJhZ2UiOjM1fQ.zt3sQAm2-9gjbRSh20rjn1nAPIv3vNhgQM2-31I5DRY
Jak przetestować działanie JWT za pomocą frameworka RestAssured?
Dla prostego przypadku testowego użyję strony https://demoqa.com/. Zanim zacznę, przede wszystkim muszę przygotować kilka rzeczy, aby uzyskać token JWT. Zgodnie ze swaggerem DemoQA trzeba utworzyć użytkownika, wysyłając POST
do punktu końcowego /Account/v1/User
z danymi użytkownika. Jak to zrobić? Spójrz:
private String body = "{\n" +
" \"userName\": \"" + USERNAME + "\",\n" +
" \"password\": \"" + PASSWORD + "\"\n" +
"}";
Tak natomiast wygląda wysłanie danych użytkownika i pobranie jego identyfikatora z pola „userID” z odpowiedzi:
private void createUser() {
userID = given()
.contentType("application/json")
.body(body)
.when()
.post(USER_ENDPOINT)
.jsonPath()
.get("userID");
}
Po pomyślnym utworzeniu użytkownika nadszedł czas, aby wygenerować dla niego token. Podążając za swaggerem, muszę wysłać zapytanie typu POST
z tymi samymi danymi użytkownika na endpoint /Account/v1/GenerateToken
. Zobacz:
private void generateToken() {
token = given()
.contentType("application/json")
.body(body)
.when()
.post(GENERATE_TOKEN_ENDPOINT)
.jsonPath()
.get("token");
}
Podobnie jak w poprzednim fragmencie kodu token został pobrany z odpowiedzi json, przyjmując wartość elementu „token”.
Gotowe? Po tym wstępie mogę wykonać dwa proste przypadki testowe, wysyłając zapytanie GET
na /Account/v1/User
. W pierwszym przypadku zamierzam autoryzować żądanie za pomocą już pobranego tokena, podczas gdy w drugim nie.
Zapytanie typu „GET” wraz z autoryzacją tokenem JWT:
@Test
void getAuthorizedUser() {
given()
.contentType("application/json")
.headers("Authorization", "Bearer " + token)
.when()
.get(USER_ENDPOINT + "/" + userID)
.then()
.assertThat()
.statusCode(HttpStatus.SC_OK);
}
Zapytanie typu „GET” pozbawione tokena JWT:
@Test
void getUnauthorizedUser() {
given()
.contentType("application/json")
.when()
.get(USER_ENDPOINT + "/" + userID)
.then()
.assertThat()
.statusCode(HttpStatus.SC_UNAUTHORIZED);
}
Powyższe przypadki testowe są bardzo podobne. Jedyną różnicą jest dodanie nagłówka Authorization wraz z tokenem w jednym z żądań. Schemat Bearer jest powszechną konwencją podczas obsługi tokena JWT w nagłówku autoryzacji. Spójrz:
Authorization: Bearer /token/
Jak widzisz, odpowiedź na żądanie autoryzowanego użytkownika ma kod odpowiedzi HTTP 200. Oznacza to, że cała operacja zakończyła się pomyślnie. W drugim przypadku, gdy użytkownik jest nieautoryzowany (brak tokena w nagłówku), kod statusu odpowiedzi to 401, a więc „nieautoryzowany”.
Podsumowanie
Artykuł zawiera informacje o obsłudze tokena JSON Web Token (JWT) przy użyciu biblioteki Rest Assured. Wyjaśniłem w nim znaczenie JWT w zabezpieczaniu aplikacji internetowych i interfejsów API. Główna część artykułu to przewodnik krok po kroku dotyczący procesu implementacji uwierzytelniania JWT w Rest Assured. Obejmuje on podstawowe pojęcia, takie jak uzyskiwanie i analizowanie JWT, ustawianie nagłówków i obsługa autoryzowanych żądań. Po zapoznaniu się z nim uzyskasz podstawową wiedzę i narzędzia do pomyślnego wdrożenia i walidacji uwierzytelniania z wykorzystaniem JWT w scenariuszach testowych Rest Assured, zachowując dobre praktyki testowania API.