Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает Token?
Что такое Token
Token (токен) - это строка данных, которая служит доказательством идентичности и аутентификации пользователя при взаимодействии между клиентом (браузер) и сервером. Токен содержит информацию о пользователе в закодированном виде.
Виды Token
1. JWT (JSON Web Token) - самый популярный
JWT состоит из трёх частей, разделённых точками:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
├─ Header (заголовок)
├─ Payload (данные)
└─ Signature (подпись)
Header (закодирован в Base64):
{
"alg": "HS256", // Алгоритм подписи
"typ": "JWT" // Тип токена
}
Payload (закодирован в Base64, но НЕ зашифрован):
{
"sub": "1234567890", // ID пользователя
"name": "John Doe", // Имя
"iat": 1516239022, // Дата создания
"exp": 1516242622 // Дата истечения (через час)
}
Signature (подпись на основе Header + Payload + Secret):
HSHA256(
base64(header) + "." + base64(payload),
"your-secret-key"
)
Как работает аутентификация с Token
Шаг 1: Логин
// Клиент отправляет credentials
fetch('https://api.example.com/login', {
method: 'POST',
body: JSON.stringify({
email: 'user@example.com',
password: 'secure123'
})
})
.then(r => r.json())
.then(data => {
// Сервер вернул токен
const token = data.token;
// Сохраняем в localStorage
localStorage.setItem('authToken', token);
});
Ответ от сервера:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyQGV4YW1wbGUuY29tIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"expiresIn": 3600
}
Шаг 2: Сохранение Token
// Вариант 1: localStorage (небезопасно для sensitive данных)
localStorage.setItem('token', token);
// Вариант 2: sessionStorage (удаляется при закрытии браузера)
sessionStorage.setItem('token', token);
// Вариант 3: Cookie с флагом httpOnly (безопаснее)
// Отправляется автоматически браузером
Шаг 3: Отправка Token в запросах
// Каждый API запрос включает токен в заголовок
const token = localStorage.getItem('token');
fetch('https://api.example.com/user/profile', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(r => r.json())
.then(data => console.log(data));
Шаг 4: Проверка на сервере
// На бэкенде (Node.js + Express пример)
app.get('/user/profile', (req, res) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token' });
}
try {
// Проверяем подпись и срок действия
const decoded = jwt.verify(token, 'your-secret-key');
// decoded = { sub: 'user@example.com', ... }
// Ищем пользователя в БД
const user = await User.findById(decoded.sub);
res.json(user);
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
});
Жизненный цикл Token
┌─────────────────────────────────────────────────────┐
│ 1. Создание │
│ Сервер создает JWT с данными пользователя │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 2. Отправка клиенту │
│ HTTP ответ с токеном в body или Cookie │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 3. Сохранение │
│ Клиент сохраняет в localStorage/sessionStorage │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 4. Использование │
│ Отправляется в Authorization заголовке │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 5. Проверка │
│ Сервер проверяет подпись и дату истечения │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 6. Обновление или истечение │
│ Когда exp пройдена -> нужен новый токен │
└─────────────────────────────────────────────────────┘
Пример полной реализации на Frontend
// auth.js
class AuthService {
async login(email, password) {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (!response.ok) throw new Error('Login failed');
const { token } = await response.json();
localStorage.setItem('token', token);
return token;
}
getToken() {
return localStorage.getItem('token');
}
isAuthenticated() {
const token = this.getToken();
if (!token) return false;
// Декодируем payload (вторая часть)
const parts = token.split('.');
const payload = JSON.parse(atob(parts[1]));
// Проверяем, не истёк ли токен
const isExpired = payload.exp * 1000 < Date.now();
return !isExpired;
}
logout() {
localStorage.removeItem('token');
}
async makeRequest(url, options = {}) {
const token = this.getToken();
return fetch(url, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${token}`
}
});
}
}
Token vs Cookie
Token (JWT в localStorage):
- Отправляется вручную в заголовке
- Уязвим к XSS (JavaScript может прочитать)
- Контролируется фронтенд кодом
Cookie с httpOnly:
- Отправляется автоматически браузером
- Защищен от XSS (JavaScript не может прочитать)
- Требует CSRF защиты
Refresh Token - обновление доступа
Аксес токен живёт недолго (15 минут), а Refresh токен живёт долго (7 дней):
// Логин
const { accessToken, refreshToken } = await login(email, password);
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
// Когда accessToken истекает
async function refreshAccessToken() {
const refreshToken = localStorage.getItem('refreshToken');
const response = await fetch('/api/refresh', {
method: 'POST',
body: JSON.stringify({ refreshToken })
});
const { accessToken } = await response.json();
localStorage.setItem('accessToken', accessToken);
return accessToken;
}
Безопасность
Хорошие практики:
- Используйте HTTPS (токен может быть перехвачен)
- Храните в HttpOnly Cookie, если возможно
- Устанавливайте короткое время жизни (15-60 минут)
- Используйте Refresh токен для обновления
- Проверяйте подпись на сервере ВСЕГДА
- Не храните чувствительные данные в Payload
Плохие практики:
- Хранение в localStorage для XSS-уязвимых приложений
- Отправка пароля в токене
- Беспроверочное использование токена
Ключевые выводы
- JWT = закодированные данные + подпись
- Клиент отправляет в каждом запросе: Authorization: Bearer token
- Сервер проверяет подпись - уверен, что токен не поддельный
- Токен живёт ограниченное время - нужно обновлять
- Не зашифрован, только закодирован - не передавайте secrets в payload
- Refresh tokens помогают обновлять доступ без повторного логина