Веб-токен JSON Даrfc7519Стандарт, который использует JSON для передачи данных, чтобы определить, вошел ли пользователь в систему.
Перед jwt используйтеsession
для аутентификации пользователя.
Следующий код написан на javascript.
- Оригинальная ссылка:Блог Ямадзуки
session
Традиционный способ определить, следует ли входить в систему, — это использоватьsession + token
.
token
Относится к использованию токенов на стороне клиента в качестве учетных данных статуса пользователя, которые обычно хранятся в браузере.localStorage
илиcookie
середина.
session
Это относится к использованию базы данных redis или sql на стороне сервера для хранения парных отношений ключ-значение user_id и токена.Основной принцип работы заключается в следующем.
Использование на стороне сервераsessions
Хранить пары ключ-значение
const sessions = {
"ABCED1": 10086,
"CDEFA0": 10010
}
Каждый раз, когда клиент запрашивает данные с разрешением, токен переносится, и серверная сторона получает user_id в соответствии с токеном и сеансами для завершения процесса аутентификации.
function getUserIdByToken (token) {
return sessions[token]
}
если хранится вcookie
часто можно услышать вsession + cookie
схема входа. На самом деле хранится вcookie
,localStorage
четноеIndexedDB
илиWebSQL
Каждый из них имеет свои преимущества и недостатки, и основная идея одна и та же.
оcookie
а такжеtoken
достоинства и недостатки, вtoken authetication vs cookiesЕсть обсуждения.
Если вы не используете файлы cookie, вы можете воспользоватьсяlocalStorage + Authorization
способ аутентификации, более без гражданства
// http 的头,每次请求权限接口时,需要携带 Authorization Header
const headers = {
Authorization: `Bearer ${localStorage.get('token')}`
}
Порекомендуйте внешний репозиторийlocalForage,использовать
IndexedDB
,WebSQL
а такжеIndexedDB
Сделайте хранилище ключ-значение.
логин без гражданства
session
Необходимо хранить соответствующую информацию о пользователях и токенах в базе данных, поэтому она называетсясостояние.
Только представьте, как вы можете войти в систему, не сохраняя состояние пользователя в базе данных.
первый метод:Внешний интерфейс напрямую передает user_id на сервер
Недостаток также особенно очевиден: пользователи могут легко изменить любой user_id, а настройки разрешений бесполезны. Но мысль правильная, а то вниз.
Улучшать:Симметрично зашифровать user_id
После того, как сервер симметрично зашифрует user_id, он возвращает его клиенту в виде токена в качестве учетных данных статуса пользователя. Чуть сильнее вышеперечисленного, но из-за симметричного шифрования важнее выбрать подходящий алгоритм и ключ
Улучшать:User_id не нужно шифровать, нужно только подписать, чтобы гарантировать, что он не будет подделан
Это идея jwt: user_id, алгоритм шифрования и подпись формируют токен и сохраняют его на стороне клиента.Всякий раз, когда клиент запрашивает интерфейс, токен переносится, и сервер анализирует алгоритм шифрования и user_id в соответствии с токен, чтобы определить, является ли подпись согласованной.
Json Web Token
jwt в соответствии сHeader
,Payload
а такжеSignature
три части по.
сшиты вместе.
Header
Заголовок состоит из следующих алгоритмов и типов асимметричного шифрования.
const header = {
// 加密算法
alg: 'HS256',
type: 'jwt'
}
Payload
Полезная нагрузка поRegistered Claimи состав данных, которые необходимо передать. Эти поля данных также называютсяClaim
.
Registered Claim
более важно"exp" Claim
Указывает время истечения срока действия, которое будет установлено при входе пользователя в систему.
const payload = {
// 表示 jwt 创建时间
iat: 1532135735,
// 表示 jwt 过期时间
exp: 1532136735,
// 用户 id,用以通信
user_id: 10086
}
Signature
Signature
Зависит отHeader
,Payload
а такжеsecretOrPrivateKey
вычислено.secretOrPrivateKey
Поскольку конфиденциальные данные хранятся на стороне сервера, рассмотрите возможность использованияvault secret
илиk8s secret
заsecretOrPrivateKey
, если алгоритм шифрования используетHMAC
, то строка, еслиRSA
илиECDSA
, это PrivateKey.
// 由 HMACSHA256 算法进行签名,secret 不能外泄
const sign = HMACSHA256(base64.encode(header) + '.' + base64.encode(payload), secret)
// jwt 由三部分拼接而成
const jwt = base64.encode(header) + '.' + base64.encode(payload) + '.' + sign
Из сгенерированных правил jwt мы знаем, что клиент может анализировать полезную нагрузку, поэтому не переносите в полезную нагрузку конфиденциальные данные, такие как пароли пользователей.
процесс проверки
В правиле генерации видно, что первые две части jwt представляют собой кодировку base64 заголовка и полезной нагрузки.
После того, как сервер получает токен от клиента, он анализирует первые две части, чтобы получить заголовок и полезные данные, и использует алгоритм в заголовке для подписи с помощью secretOrPrivateKey, чтобы определить, соответствует ли он подписи, содержащейся в jwt.
С вопросом, как судить о сроке действия токена?
применение
Из приведенного выше видно, что jwt не шифрует данные, а подписывает данные, чтобы гарантировать, что они не будут подделаны.Помимо использования при входе в систему, его также можно использовать для проверки электронной почты, графического кода подтверждения и кода подтверждения SMS.
Капча
При входе в систему, если вы введете неправильный пароль слишком много раз, появится графический код подтверждения.
Принцип графического кода проверки заключается в том, чтобы предоставить клиенту графику и сохранить строку в паре с изображением на стороне сервера, что в прошлом в основном реализовывалось сеансом.
Строка в паре с проверочным кодом может использоваться в качестве секрета для проверки без сохранения состояния.
const jwt = require('jsonwebtoken')
// 假设验证码为字符验证码,字符为 ACDE,10分钟失效
const token = jwt.sign({}, secrect + 'ACDE', { expiresIn: 60 * 10 })
const codeImage = getImageFromString('ACDE')
// 给前端的响应
const res = {
// 验证码图片的 token,从中可以校验前端发送的验证码
token,
// 验证码图片
codeImage,
}
SMS-код подтверждения совпадает с графическим кодом подтверждения.
Подтверждение по элетронной почте
Теперь веб-сайт будет проверять почтовый ящик после успешной регистрации.Конкретный метод заключается в отправке ссылки на почтовый ящик, и пользователь щелкает ссылку, и проверка проходит успешно.
// 把邮箱以及用户id绑定在一起
const code = jwt.sign({ email, userId }, secret, { expiresIn: 60 * 30 })
// 在此链接校验验证码
const link = `https://example.com/code=${code}`
Без гражданства против с сохранением состояния
Что касается stateless и stateful, то есть сравнения и в других технических направлениях, таких как React’sstateLess component
а такжеstateful component
, побочные эффекты в функциональном программировании можно понимать как состояние, а http также является протоколом без сохранения состояния, который должен полагаться на заголовки и файлы cookie для переноса состояния.
В аутентификации пользователей состояние означает, следует ли полагаться на внешнее хранилище данных, такое как mysql, redis и т. д.
кейс
Рассмотрите следующие вопросы о входе в систему с использованием сеанса и реализации jwt, чтобы они были более понятными.jwt
сценарии использования
Как я могу аннулировать этот токен, когда пользователь выходит из системы
Поскольку jwt не имеет состояния и не сохраняет информацию об устройстве пользователя, он не может просто использовать ее для решения вышеуказанных проблем.Вы можете использовать базу данных для сохранения некоторых состояний для завершения.
-
session
: Просто очистите токен, соответствующий user_id -
jwt
: Используйте Redis для поддержания черного списка. Когда пользователь выходит из системы, токен добавляется в черный список. Время истечения согласуется с временем истечения срока действия JWT.
Как разрешить пользователям входить в систему только на одном устройстве, например WeChat
-
session
: использовать базу данных sql, добавить поле токена и индекс в таблицу пользовательской базы данных, сбрасывать поле токена каждый раз, когда вы входите в систему, и находить user_id в соответствии с токеном каждый раз, когда запрос требует интерфейса разрешений. -
jwt
: Если вы используете базу данных типа sql, добавьте поле токена в таблицу пользовательской базы данных (не нужно добавлять индекс), сбрасывайте поле токена каждый раз, когда вы входите в систему, и каждый раз, когда вы запрашиваете интерфейс разрешений, получайте user_id в соответствии с на jwt и проверьте таблицу пользователей в соответствии с user_id, чтобы получить оценку токена. Согласован ли токен. В качестве альтернативы вы можете использовать метод счетчика, как в следующем вопросе.
Для этого требования сессия немного проще, ведь jwt тоже должен полагаться на базу данных.
Как разрешить пользователям входить в систему только на последних пяти устройствах, таких как многие игроки
-
session
: Создайте таблицу базы данных токенов, используя sql-подобную базу данных с тремя полями: id, token и user_id.Таблицы пользователей и токенов имеют отношение 1:m. Добавьте строку для каждого входа. Получите user_id в соответствии с токеном, а затем получите количество устройств, на которых пользователь вошел в систему в соответствии с user_id.Если их больше 5, удалите строку с наименьшим идентификатором. -
jwt
: использовать счетчик, использовать базу данных sql, добавить счетчик полей в пользовательскую таблицу, значение по умолчанию равно 0, поле счетчика увеличивается на 1 при каждом входе в систему, а полезная нагрузка jwt, создаваемая при каждом входе в систему, содержит данные current_count значение счетчика пользователя. Каждый раз, когда запрашивается интерфейс разрешений, счетчик и текущий_счет получаются из jwt, а счетчик получается из пользовательской таблицы в соответствии с user_id, и если разница с текущим_счетом меньше 5
Для этого требования jwt немного проще, а использование сеанса требует ведения дополнительной таблицы токенов.
Как разрешить пользователям входить в систему только на последних пяти устройствах и заставить пользователя отключать все другие устройства, кроме существующего устройства, например, многих игроков
-
session
: на основании предыдущего вопроса удалите все записи токенов, кроме устройства. -
jwt
: На основании предыдущего вопроса считай +5, и переназначь устройство на новый кол.
Как отобразить список устройств, на которых зарегистрирован этот пользователь / Как выгнать определенного пользователя
-
session
: добавить новое столбцовое устройство в таблицу токенов. -
jwt
: Сервер должен хранить информацию о списке устройств. Практика такая же, как и сеанс. Использование jwt не имеет смысла.
Суммировать
Из приведенных выше вопросов, если вам не нужно контролировать количество зарегистрированных устройств и информацию об устройстве, jwt без сохранения состояния является хорошим выбором. Как только информация об устройстве задействована, в jwt необходимо добавить дополнительную поддержку состояния, что усложняет аутентификацию.В этом случае сеанс является хорошим выбором.
jwt не является панацеей.Использовать или не использовать jwt нужно решать в соответствии с потребностями бизнеса.
Я Shanyue, программист, обожаю бегать и лазить по горам, буду регулярно выкладывать full-stack статьи в личном паблике. Если вас интересуют интервью с полным стеком, фронтенд-инжиниринг, graphql, devops, эксплуатация и обслуживание персональных серверов и микросервисы, вы можете подписаться на меня