Реклама ООО Таймвэб
Реклама ООО Таймвэб

Авторизация и аутентификация пользователя при помощи JWT. Часть 1: Что такое JWT и как его создать?

1 комментарий
Авторизация и аутентификация пользователя при помощи JWT. Часть 1: Что такое JWT и как его создать?
Реклама. ООО «ТаймВэб». erid: LjN8KaXqo

Что такое JWT?

JWT или JSON Web Token представляет собой надежный и безопасный метод передачи информации между сторонами в виде JSON-объектов. Не просто так этот метод один из наиболее популярных в мире.

JWT (далее токен) состоит из трех частей, закодированных в формате Base64. Эти части разделены между собой точками.

header

Первая часть токена является заголовком. Содержит в себе алгоритм шифрования подписи (наш signature) и тип токена (JWT/JWE/JWS). В большинстве случаев при использовании библиотек или сервисов по генерации токенов заголовок выставляется автоматически.

Для ручного варианта напишем функцию createBase64String(), которая будет принимать в себя javascript-объект и вернет готовую строку в формате base64:

const myHeader = {
    alg: 'HS256',
    typ: 'JWT',
}

const createBase64String = (object) => {
    const jsonObject = JSON.stringify(object);
    return btoa(jsonObject)
}

const header = createBase64String(myHeader);
console.log(header) // 'eyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9'

1) Мы создаем объект с нужными заголовками.
2) Преобразовываем его в JSON-строку.
3) Встроенной в JS функцией btoa() кодируем в base64.
4) Теперь header содержит в себе строку 'eyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9'.

payload

Вторая часть содержит в себе пользовательские данные – любые, какие захотим. Однако нужно иметь ввиду, что включать сюда sensitive-информацию (например, пароли в явном виде, ключи, хэши паролей и т.д.) не стоит. Сюда мы можем поместить информацию о времени создания токена (iat), даты окончания (exp), id пользователя и тд. Другими словами, любую информацию, владение которой не сильно поможет хакеру, ну а нам даст своеобразную маркировку на конкретного пользователя.

Пример из моего проекта: iat, exp – указываются в формате UNIX-времени. То есть количестве секунд, прошедших с начала «UNIX-эпохи» (1 января 1970 г. 00ч 00м 00с по UTC):

const myPayload = {
    nickname: "userNickname",
    deviceId: "userDeviceId",
    iat: 9999999,
    exp: 9999999,
}

const payload = createBase64String(myPayload);

console.log(payload) //"eyJuaWNrbmFtZSI6InVzZXJOaWNrTmFtZSIsImRldmljZUlkIjoidXNlckRldmljZUlkIiwiaWF0Ijo5OTk5OTk5LCJleHAiOjk5OTk5OTl9"

1) Создаем объект и включаем в него нужные данные.
2) Пользуемся ранее созданной функцией и передаем туда наш новый объект.
3) Полученная строка лежит в переменной payload.

signature

Пожалуй, самая важная и ответственная часть JWT – это подпись. Подпись является строкой, которая генерируется в результате хэширования строк header и payload, разделенных точкой, и последующей кодировкой хэша в base64 (стало сложновато, давайте пошагово).

Нам нужно сперва создать подпись HMAC-SHA256 (далее просто хмак) из следующей строки и суперсекретного ключа:

const superKey = 'Этот секретный ключ нельзя никому показывать и передавать!'
const myString = header + '.' + payload;
// eyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9.eyJuaWNrbmFtZSI6InVzZXJOaWNrTmFtZSIsImRldmljZUlkIjoidXNlckRldmljZUlkIiwiaWF0Ijo5OTk5OTk5LCJleHAiOjk5OTk5OTl9

Секретный ключ может быть абсолютно любой, даже просто «а». Его нужно самостоятельно придумать, записать и после прочтения сжечь... Ну или просто никому не показывать и не передавать, ведь он нам еще понадобится для декодирования токенов.

Так как JS не имеет встроенных функций для создания подписи хмак, необходимо воспользоваться какой-нибудь сторонней библиотекой (например, CryptoJS). Но мы такими самодурствами заниматься не будем и просто предположим, что получили нужную подпись. Ведь вышенаписанная информация нужна для понимания всего процесса создания токена и общего развития, на практике же мы будем пользоваться готовой библиотекой jsonwebtoken.

После получения подписи необходимо и ее закодировать в base64:

const sign = // Тут мы получили подпись и преобразовали ее в строку
const signature = btoa(sign)

Таким образом в signature будет лежать строка (например: LxTQVx8JgzSBPyG0pSf7Z9Ojo4N7442loY0k1POK1v4), расшифровать которую без суперсекретного ключа нельзя, либо очень-очень сложно (почти невозможно).

Объединив все три части точками, мы получим наш токен:

eyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9.eyJuaWNrbmFtZSI6InVzZXJOaWNrTmFtZSIsImRldmljZUlkIjoidXNlckRldmljZUlkIiwiaWF0Ijo5OTk5OTk5LCJleHAiOjk5OTk5OTl9.LxTQVx8JgzSBPyG0pSf7Z9Ojo4N7442loY0k1POK1v4

«Чота сложна, мож попроще как-нить?»

Да, можно намного проще. Для этого нам понадобится библиотека с открытым исходным кодом. В нашем случае это jsonwebtoken:

Установим через npm:

npm i jsonwebtoken

Далее просто импортируем и воспользуемся методом .sign(payload, secretKey, options):

import jwt from 'jsonwebtoken';
const payload = {
    id: 12,
    name: 'Alesha',
    city: 'Moscow',
}
const secretKey = 'EzPzLmnSqzy';
const options = {
    expiresIn: '10m'
}

const token = jwt.sign(payload, secretKey, options)
Итак:
1. Мы определили нашу полезную нагрузку (payload). Разумеется, мы не включаем сюда никаких чувствительных данных. Имя к таковым не относится (наверное...). iat и exp библиотека вставляет автоматически, так что явно их указывать не нужно.

2. Мы придумали секретный ключ. Он довольно простой, но на боевом сервере лучше определить что-то более надежное =)

3. В options передаются опции, которые можно найти в официальной документации к библиотеке. Мы выбрали только expiresIn, который определяет срок годности токена (тот самый exp).

В результате в нашей переменной токен будет лежать наш свеженький JWT со сроком действия 10 минут. 

Проверить токен можно с помощью метода .verify(token, secretKey, callback(err, decoded)), о чем я раскажу в следующей части статьи.

Комьюнити теперь в Телеграм
Подпишитесь и будьте в курсе последних IT-новостей
Подписаться

Итоги

  • Пользуемся библиотеками с открытым кодом, чтобы быть уверенными, что наши данные никуда не утекают.
  • Не тратим время на самодеятельность по собственноручному созданию токенов (время разработчика дорогое).
  • Лайкаем, подписываемся и ждем следующих моих постов.
Hello World! Гайды и обзоры для девелоперов разных мастей.

Комментарии

Владимир +5
16 дек в 15:52
норм
С помощью соцсетей
У меня нет аккаунта Зарегистрироваться
С помощью соцсетей
У меня уже есть аккаунт Войти
Инструкции по восстановлению пароля высланы на Ваш адрес электронной почты.
Пожалуйста, укажите email вашего аккаунта
Ваш баланс 10 ТК
1 ТК = 1 ₽
О том, как заработать и потратить Таймкарму, читайте в этой статье
Чтобы потратить Таймкарму, зарегистрируйтесь на нашем сайте