Введение в OAuth 2.0 и JWT на C++
Современные веб-приложения и API редко обходятся без систем авторизации. Два самых популярных стандарта — OAuth 2.0 и JWT (JSON Web Token) — стали основой безопасности для миллионов сервисов. В этой статье мы разберём, как реализовать базовую OAuth 2.0 авторизацию с JWT токенами на языке C++. Вы узнаете, как работают эти протоколы, и увидите готовые примеры кода, которые можно адаптировать под свой проект.
Статья ориентирована на начинающих разработчиков, которые уже знакомы с основами C++ (классы, функции, работа с сетью) и хотят добавить в свои приложения безопасную авторизацию. Мы не будем использовать сторонние библиотеки для HTTP-сервера — все примеры будут на чистом C++ с минимальными зависимостями.
Что такое OAuth 2.0 и зачем он нужен?
OAuth 2.0 — это протокол авторизации, который позволяет приложениям получать ограниченный доступ к ресурсам пользователя без передачи его пароля. Представьте, что вы хотите дать приложению доступ к вашим фотографиям на сервере. Вместо того чтобы вводить логин и пароль, вы проходите через Authorization Server, который выдаёт временный токен. Приложение использует этот токен для доступа к ресурсам.
Основные роли в OAuth 2.0:
- Resource Owner — пользователь, владелец данных.
- Client — приложение, которое запрашивает доступ.
- Authorization Server — сервер, который выдаёт токены после аутентификации.
- Resource Server — сервер, хранящий защищённые данные (например, API).
На C++ мы реализуем упрощённую версию Authorization Server и Resource Server, используя JWT в качестве токена доступа.
JWT: структура и принцип работы
JWT (JSON Web Token) — это компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. Токен состоит из трёх частей, разделённых точками:
header.payload.signature
Header содержит тип токена и алгоритм подписи (обычно HMAC SHA256 или RSA). Payload — это полезная нагрузка: идентификатор пользователя, время жизни токена, роли и т.д. Signature — подпись, которая проверяет целостность данных.
Пример создания JWT на C++ без библиотек (упрощённо):
#include <iostream>
#include <sstream>
#include <vector>
#include <openssl/sha.h>
#include <openssl/hmac.h>
std::string base64_encode(const std::string &input) {
// Упрощённая реализация Base64 (для примера)
static const char* lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string result;
// ... код кодирования ...
return result;
}
std::string create_jwt(const std::string &payload, const std::string &secret) {
std::string header = R"({"alg":"HS256","typ":"JWT"})";
std::string header_b64 = base64_encode(header);
std::string payload_b64 = base64_encode(payload);
std::string data = header_b64 + "." + payload_b64;
unsigned char* sig = HMAC(EVP_sha256(), secret.c_str(), secret.length(),
(unsigned char*)data.c_str(), data.length(), NULL, NULL);
std::string sig_b64 = base64_encode(std::string((char*)sig, 32));
return data + "." + sig_b64;
}
int main() {
std::string payload = R"({"user_id":123,"role":"admin","exp":1700000000})";
std::string token = create_jwt(payload, "my_secret_key");
std::cout << "JWT: " << token << std::endl;
return 0;
}
Этот код создаёт JWT с заголовком HS256 и полезной нагрузкой. В реальных проектах используйте проверенные библиотеки, такие как jwt-cpp или libjwt, но для понимания сути подойдёт и такой пример.
Реализация OAuth 2.0 сервера на C++
Теперь объединим OAuth 2.0 и JWT. Наш сервер будет:
- Принимать запросы на авторизацию (логин/пароль).
- Выдавать JWT токен доступа.
- Проверять токен при обращении к защищённым ресурсам.
Шаг 1: Базовая структура HTTP-сервера
Для простоты используем сокеты POSIX. Создадим класс OAuthServer:
#include <string>
#include <map>
#include <functional>
#include <netinet/in.h>
class OAuthServer {
public:
OAuthServer(int port) : port_(port) {}
void start() {
// Создание сокета, привязка, прослушивание
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port_);
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
while (true) {
int client_fd = accept(server_fd, nullptr, nullptr);
handle_request(client_fd);
close(client_fd);
}
}
private:
int port_;
std::map<std::string, std::string> users_; // user_id -> password hash
void handle_request(int client_fd) {
// Парсинг HTTP запроса, маршрутизация
// Если путь /oauth/token -> process_login()
// Если путь /api/resource -> verify_token()
}
};
Шаг 2: Обработка логина и выдача JWT
Когда пользователь отправляет POST-запрос с логином и паролем, сервер проверяет учётные данные и возвращает JWT:
std::string process_login(const std::string &username, const std::string &password) {
// Проверка пароля (в реальности — хеширование)
if (users_.find(username) == users_.end() || users_[username] != password) {
return "HTTP/1.1 401