JSON Web Token i jego obsługa w RestAssured

Tomasz Niegowski

Wprowadzenie do JWT

JWT, skrót od 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, JWT jest jak cyfrowy paszport lub dowód osobisty, który zawiera zakodowane informacje o użytkowniku lub encji.

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ść zawiera rzeczywiste dane lub stwierdzenia (’claims’), które mogą zawierać informacje, takie jak identyfikator użytkownika, rola, uprawnienia i inne istotne szczegóły. Stwierdzenia te są zakodowane jako obiekt JSON.

Aby zapewnić integralność i autentyczność tokena, podpis jest generowany przez połączenie nagłówka, zawartości i tajnego klucza znanego tylko serwerowi. Podpis ten jest dodawany do tokena, dzięki czemu jest on odporny na manipulacje. Gdy token zostanie odebrany przez serwer, może on 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 w prosty sposób przetestować działanie JWT za pomocą frameworka RestAssured

Dla mojego prostego przypadku testowego użyję strony https://demoqa.com/, która umożliwi nam przeprowadzenie testowania.

Przede wszystkim musimy przygotować kilka rzeczy, aby uzyskać token JWT. Zgodnie ze swaggerem DemoQA, powinienem utworzyć użytkownika wysyłając POST do punktu końcowego /Account/v1/User z danymi użytkownika:

private String body = "{\n" +
  "  \"userName\": \"" + USERNAME + "\",\n" +
  "  \"password\": \"" + PASSWORD + "\"\n" +
"}";

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, musimy wysłać zapytanie typu POST z tymi samymi danymi użytkownika na endpoint /Account/v1/GenerateToken:

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’.

Po tym wstępie możemy wykonać dwa proste przypadki testowe wysyłając zapytanie GET na /Account/v1/User. W pierwszym przypadku zamierzamy 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:

Authorization: Bearer /token/

Jak widzimy, odpowiedź na żądanie autoryzowanego użytkownika posiada kod odpowiedzi HTTP 200, oznaczający, iż 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 (nieautoryzowany).

Podsumowanie

Artykuł zawiera podstawowy przewodnik po obsłudze tokena JSON Web Token (JWT) przy użyciu biblioteki Rest Assured. Wyjaśniono znaczenie JWT w zabezpieczaniu aplikacji internetowych i interfejsów API. Główna część artykułu dotyczy krok po kroku 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 przeczytaniu tego artykułu 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.

Bibliografia

Poznaj mageek of j‑labs i daj się zadziwić, jak może wyglądać praca z j‑People!

Skontaktuj się z nami