Uwierzytelnianie za pomocą tokenów JWT w WordPress REST API
This article explains a simple method for authenticating users using JWT tokens in a WordPress REST API. It provides an example code for verifying tokens and returning data, along with guidance on securing and handling user access.
W tym artykule pokażemy, jak utworzyć dedykowany endpoint w WordPress REST API. W tym celu będziemy potrzebować biblioteki PHP, która pomoże nam generować i dekodować tokeny JWT. Bibliotekę znajdziesz tutaj: Firebase PHP-JWT.
Krok 1: Instalacja biblioteki
Pierwszym krokiem jest zainstalowanie biblioteki za pomocą Composera. Uruchom w swoim projekcie następujące polecenie:
composer require firebase/php-jwt
Jeśli nie wiesz, jak korzystać z Composera w swoim projekcie, zapoznaj się z tym szczegółowym poradnikiem
Krok 2: Tworzenie klasy dla dedykowanej przestrzeni nazw API
Po zainstalowaniu biblioteki utworzymy dedykowaną klasę, która posłuży do skonfigurowania nowej przestrzeni nazw dla naszego niestandardowego API.
Krok 3: Rejestrowanie przestrzeni nazw
Aby utworzyć nową przestrzeń nazw, musimy użyć hooka akcji rest_api_init:
add_action( 'rest_api_init', [ $this, 'register_new_rest_routes' ] );
Krok 4: Tworzenie funkcji do rejestrowania tras
Następnie utworzymy funkcję obsługującą, która doda nową przestrzeń nazw. Oto kompletny kod tej funkcji:
/**
* Register route.
*
* @return void
*/
public function register_new_rest_routes(): void {
register_rest_route(
self::CUSTOM_API_NAMESPACE,
'/auth',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'auth_callback' ],
'permission_callback' => '__return_true',
'args' => [
'email' => [
'type' => 'string',
'required' => true,
'format' => 'email',
'validate_callback' => function ( $param ) {
return filter_var( $param, FILTER_VALIDATE_EMAIL );
},
],
'password' => [
'type' => 'string',
'required' => true,
'validate_callback' => function ( $param ) {
return filter_var( $param, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
},
],
],
]
);
register_rest_route(
self::CUSTOM_API_NAMESPACE,
'/get-posts',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_post_callback' ],
'permission_callback' => '__return_true',
]
);
}
Wyjaśnienie kodu
Funkcja register_rest_route() rejestruje nowe endpointy.
- Trzeci parametr: Tablica argumentów:
- self::CUSTOM_API_NAMESPACE: Dla uproszczenia nazwę przestrzeni nazw przechowuję w stałej.
- Drugi parametr: Określa endpoint, w tym przypadku „auth”, który obsługuje uwierzytelnianie użytkownika i zwraca wygenerowany token.
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'auth_callback' ],
'permission_callback' => '__return_true',
'args' => [
'email' => [
'type' => 'string',
'required' => true,
'format' => 'email',
'validate_callback' => function ($param) {
return filter_var($param, FILTER_VALIDATE_EMAIL);
},
],
'password' => [
'type' => 'string',
'required' => true,
'validate_callback' => function ($param) {
return filter_var($param, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
},
],
],
]
- methods: Specifies the HTTP method (GET, POST, PUT, PATCH, DELETE). It’s best practice to use built-in constants from the WP_REST_Server class:
WP_REST_Server::READABLE // GET
WP_REST_Server::CREATABLE // POST
WP_REST_Server::EDITABLE // POST, PUT, PATCH
WP_REST_Server::DELETABLE // DELETE
WP_REST_Server::ALLMETHODS // GET, POST, PUT, PATCH, DELETE
- callback: Funkcja, która przetwarza żądanie i zwraca dane użytkownikowi.
- permission_callback: Funkcja, która sprawdza poziom dostępu użytkownika. W tym przypadku zawsze zwraca wartość true.
- args: Tablica parametrów przekazywanych do API:
- type: Typ danych (int, string, bool itp.). Zaleca się określenie typu.
- required: Określa, czy parametr jest wymagany.
- format: Dodatkowy format ciągu znaków (date-time, uri, email, ip, uuid, hex-color).
- validate_callback: Funkcja służąca do walidacji danych wejściowych, często używana jako funkcja anonimowa.
Funkcja callback obsługująca uwierzytelnianie
Następnie tworzymy funkcję obsługującą auth_callback, która przyjmuje jeden parametr — instancję klasy WP_REST_Request zawierającą wszystkie przesłane dane.
Aby uzyskać dostęp do danych wejściowych, używamy funkcji get_json_params(), która zwraca wszystkie parametry w postaci tablicy.
Weryfikujemy adres e-mail, aby upewnić się, że użytkownik istnieje w bazie danych. Jeśli nie, zwracamy odpowiedź z błędem. Takie podejście, znane jako wczesny return (early return), zwiększa wydajność serwera.
Następnie tworzymy klucz dla naszego tokenu JWT, wykorzystując AUTH_KEY, jeśli jest zdefiniowany, lub własną stałą jako rozwiązanie awaryjne.
Na koniec generujemy token JWT za pomocą funkcji statycznej JWT::encode() dostępnej w bibliotece:
$jwt = JWT::encode(
[
'email' => $params['email'],
'password' => $params['password'],
],
$key,
'HS256'
);
Możesz zastosować dodatkowe środki bezpieczeństwa, takie jak przechowywanie tokenu w bazie danych lub dodatkowe szyfrowanie. Więcej informacji na temat korzystania z biblioteki znajdziesz tutaj: firebase/php-jwt.
Uwaga: Ten kod służy wyłącznie do celów edukacyjnych i nie jest zalecany do stosowania w projektach produkcyjnych bez wdrożenia dodatkowych środków bezpieczeństwa.
Pełna funkcja callback obsługująca uwierzytelnianie
/**
* Auth callback.
*
* @param WP_REST_Request $request Params.
*
* @return WP_REST_Response
*/
public function auth_callback(WP_REST_Request $request): WP_REST_Response {
$params = $request->get_json_params();
if (!email_exists($params['email'])) {
return new WP_REST_Response(
[
'error' => __('User does not exist', 'domain'),
],
403
);
}
$key = defined('AUTH_KEY') ? AUTH_KEY : self::CUSTOM_API_AUTH_KEY_SALT;
$jwt = JWT::encode(
[
'email' => $params['email'],
'password' => $params['password'],
],
$key,
'HS256'
);
// ...Additional processing or database storage.
return new WP_REST_Response(
[
'token' => $jwt,
],
200
);
}
Jeśli wszystko zostało wykonane poprawnie, powinniśmy otrzymać następującą odpowiedź:

Przyjrzyjmy się teraz, jak możemy zweryfikować ten token i zwrócić dane, jeśli token jest prawidłowy. W tym celu zarejestrowałem kolejny endpoint o nazwie get-posts. Endpoint ten nie będzie przyjmował żadnych parametrów, ale sprawdzi obecność naszego tokenu i, jeśli token będzie prawidłowy, zwróci dane.
Krok po kroku przeanalizujmy funkcję obsługującą to żądanie. W pierwszej kolejności należy pobrać nagłówek autoryzacji zawierający przekazany token. W tym celu użyjemy standardowej funkcji klasy get_header(‘authorization’) z kluczem ‘authorization‘. Oto przykład żądania w Postmanie:

Korzystam z uwierzytelniania za pomocą tokenu Bearer, co oznacza, że nagłówek zwróci nie tylko nasz token, ale również ciąg Bearer TOKEN, dlatego musimy usunąć część „Bearer” oraz wszystkie dodatkowe spacje. W tym celu możemy użyć funkcji str_replace, w której po prostu zastąpimy pierwszą część pustym ciągiem, uzyskując właściwy token.
Do prawidłowego odszyfrowania tokenu potrzebujemy również soli, której użyliśmy podczas jego generowania.
Do odszyfrowania tokenu użyjemy funkcji statycznej JWT::decode. Pierwszym parametrem jest nasz token, natomiast drugi wymaga utworzenia nowej instancji klasy Key z biblioteki JWT. Przekazujemy dwa parametry: naszą sól oraz metodę używaną do dekodowania, która w moim przypadku to HS256.
Jeśli wszystko się zgadza, otrzymamy zdekodowany token wraz z zawartymi w nim parametrami. Następnie używam funkcji wp_signon, która służy do uwierzytelniania użytkownika na podstawie nazwy użytkownika/adresu e-mail oraz hasła. W przypadku nieudanego uwierzytelnienia zwróci ona instancję klasy WP_Error.
Kolejnym krokiem jest sprawdzenie odpowiedzi funkcji wp_signon. Jeśli zwróci ona błąd, natychmiast odrzucamy żądanie użytkownika dotyczące dostępu do danych.
Następnie należy napisać kod odpowiedzialny za Twoją logikę biznesową, upewniając się, że użytkownik istnieje w systemie. Przed zwróceniem jakichkolwiek danych z serwera warto również sprawdzić jego poziom dostępu. Ponieważ korzystamy z funkcji wp_signon, powinna ona zwrócić pełny obiekt WP_User, dzięki czemu będziemy mieć dostęp do wszystkich danych tej klasy.
Oto pełny kod tej funkcji:
/**
* Get some data.
*
* @param WP_REST_Request $request Request.
*
* @return WP_REST_Response
*/
public function get_post_callback( WP_REST_Request $request ): WP_REST_Response {
$header_token = $request->get_header( 'authorization' );
$token = str_replace( 'Bearer ', '', $header_token );
$key = defined( 'AUTH_KEY' ) ? AUTH_KEY : self::CUSTOM_API_AUT_KEY_SALT;
$decode_token = JWT::decode( $token, new Key( $key, 'HS256' ) );
$user = wp_signon(
[
'user_login' => $decode_token->email,
'user_password' => $decode_token->password,
],
false
);
if ( is_wp_error( $user ) ) {
return new WP_REST_Response(
[
'error' => __( 'Incorrect access token', 'domain' ),
],
403
);
}
// ... The code that your API returns.
return new WP_REST_Response(
[
'error' => null,
'response' => [ 'data' => 'Some data' ],
],
200
);
}
W tym artykule omówiliśmy prostą metodę uwierzytelniania oraz wykorzystanie tokenów JWT w projekcie. Ten kod został przygotowany wyłącznie jako przykład i nie powinien być używany w działającym projekcie produkcyjnym.
Pełny kod tej klasy znajdziesz na moim GitHubie pod tym adresem: https://github.com/alex-l-iwpdev/test-theme/tree/REST-JWT
Podsumowanie
Integracja uwierzytelniania za pomocą tokenów JWT z WordPress REST API zapewnia bezpieczny i wydajny sposób zarządzania dostępem użytkowników oraz ochrony poufnych danych. Dzięki zastosowaniu odpowiedniej walidacji tokenów możesz zapewnić sprawny proces uwierzytelniania i zwiększyć ogólny poziom bezpieczeństwa API, co sprawia, że rozwiązanie to dobrze sprawdza się w nowoczesnych aplikacjach internetowych. Ponieważ bezpieczeństwo pozostaje jednym z najważniejszych aspektów, wykorzystanie JWT wraz z metodami takimi jak uwierzytelnianie za pomocą tokenu Bearer pozwala ograniczyć dostęp do zasobów wyłącznie do autoryzowanych użytkowników. Ma to kluczowe znaczenie w przypadku aplikacji przetwarzających dane użytkowników lub wymagających bezpiecznej komunikacji z API.
Gotowy, aby wynieść swój projekt
na wyższy poziom?
Wprowadźmy Twoją wizję w życie dzięki profesjonalnemu tworzeniu stron i dedykowanym rozwiązaniom.
Skontaktuj się z nami już teraz i rozpocznijmy pracę nad przekształceniem Twoich pomysłów w rzeczywistość!