jwt практика и сравнение с сессией

база данных SQL React.js

Веб-токен JSON Даrfc7519Стандарт, который использует JSON для передачи данных, чтобы определить, вошел ли пользователь в систему.

До jwt сеанс использовался для аутентификации пользователя.

Следующий код написан на javascript.

Смотрите оригинальную ссылкуБлог Ямадзуки

session

Традиционный способ входа — использоватьsession + token.

tokenОтносится к использованию токенов на стороне клиента в качестве учетных данных статуса пользователя, которые обычно хранятся в браузере.localStorageилиcookieсередина.

sessionЭто относится к использованию базы данных redis или sql на стороне сервера для хранения парных отношений ключ-значение user_id и токена.Основной принцип работы заключается в следующем.

const sessions = {
  "ABCED1": 10086,
  "CDEFA0": 10010
}

// 通过 token 获取 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 не нужно шифровать, нужно только подписать, чтобы гарантировать, что он не будет подделан

В этом и заключается идея jwt, user_id, алгоритма шифрования и подписи, которые хранятся у клиента вместе, и каждый раз, когда запрашивается интерфейс, сервер оценивает согласованность подписи.

Json Web Token

просто по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

ВойтиHeader,Payloadа такжеsecretOrPrivateKeyвычислено.

за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 не шифрует данные, а подписывает данные, чтобы гарантировать, что они не будут подделаны. Помимо использования при входе в систему, его также можно использовать для проверки электронной почты и графического кода подтверждения.

Капча

При входе в систему, если вы введете неправильный пароль слишком много раз, появится графический код подтверждения.

Принцип графического кода проверки заключается в том, чтобы предоставить клиенту графику и сохранить строку в паре с изображением на стороне сервера, что в прошлом в основном реализовывалось сеансом.

Строка в паре с проверочным кодом может использоваться в качестве секрета для проверки без сохранения состояния.

const jwt = require('jsonwebtoken')

// 假设验证码为字符验证码,字符为 ACDE,10分钟失效
const token = jwt.sign({ userId: 10085 }, secrect + 'ACDE', { expiresIn: 60 * 10 })

Подтверждение по элетронной почте

Теперь веб-сайт будет проверять почтовый ящик после успешной регистрации.Конкретный метод заключается в отправке ссылки на почтовый ящик, и пользователь щелкает ссылку, и проверка проходит успешно.

// 把邮箱以及用户id绑定在一起
const code = jwt.sign({ email, userId }, secret, { expiresIn: 60 * 30 })

// 在此链接校验验证码
const link = `https://example.com/code=${code}`

Без гражданства против с сохранением состояния

Что касается stateless и stateful, есть также сравнения в других технических направлениях, таких как компонент React без состояния и компонент с состоянием.Побочные эффекты в функциональном программировании можно понимать как состояние, а http также является протоколом без состояния, для которого требуются заголовки и файлы cookie для переноса. государство.

В аутентификации пользователей состояние означает, следует ли полагаться на внешнее хранилище данных, такое как mysql, redis и т. д.

Подумайте, как использовать сеанс и jwt для реализации следующих вопросов о входе в систему.

Как я могу аннулировать этот токен, когда пользователь выходит из системы

Поскольку jwt не имеет состояния и не сохраняет информацию об устройстве пользователя, он не может просто использовать ее для решения вышеуказанных проблем.Вы можете использовать базу данных для сохранения некоторых состояний для завершения.

  • сеанс: просто очистите токен, соответствующий user_id
  • jwt: используйте redis для ведения черного списка и добавляйте черный список (подпись) при выходе пользователя из системы.Время истечения срока действия соответствует времени истечения срока действия jwt.

Как разрешить пользователям входить в систему только на одном устройстве, например WeChat

  • сеанс: использовать базу данных sql, добавить поле токена и индекс в таблицу пользовательской базы данных, сбросить поле токена каждый раз, когда вы входите в систему, и найти user_id в соответствии с токеном каждый раз, когда вы запрашиваете интерфейс разрешений.
  • jwt: если вы используете базу данных типа sql, добавьте поле токена в таблицу пользовательской базы данных (не нужно добавлять индекс), сбрасывайте поле токена каждый раз, когда вы входите в систему, и каждый раз, когда вы запрашиваете интерфейс разрешений, получайте user_id в соответствии с jwt и проверьте таблицу пользователей в соответствии с user_id, чтобы получить токен. Определите, согласованы ли токены. В качестве альтернативы вы можете использовать метод счетчика, как в следующем вопросе.

Для этого требования сессия немного проще, ведь jwt тоже должен полагаться на базу данных.

Как разрешить пользователям входить в систему только на последних пяти устройствах, таких как многие игроки

  • сеанс: используйте базу данных типа sql для создания таблицы базы данных токенов с тремя полями: идентификатор, токен и user_id.Таблицы пользователей и токенов имеют отношение 1: m. Добавьте строку для каждого входа. Получите user_id в соответствии с токеном, а затем получите количество устройств, на которых пользователь вошел в систему в соответствии с user_id.Если их больше 5, удалите строку с наименьшим идентификатором.
  • jwt: используйте счетчик, используйте базу данных sql, добавьте счетчик полей в пользовательскую таблицу, значение по умолчанию равно 0, поле счетчика увеличивается на 1 каждый раз, когда вы входите в систему, а полезная нагрузка jwt, создаваемая при каждом входе в систему, содержит данные current_count — это значение счетчика пользователя. Каждый раз, когда запрашивается интерфейс разрешений, счетчик и текущий_счет получаются из jwt, а счетчик получается из пользовательской таблицы в соответствии с user_id, и если разница с текущим_счетом меньше 5

Для этого требования jwt немного проще, а использование сеанса требует ведения дополнительной таблицы токенов.

Как разрешить пользователям входить в систему только на последних пяти устройствах и заставить пользователя отключать все другие устройства, кроме существующего устройства, например, многих игроков

  • сеанс: на основе предыдущего вопроса удалите все записи токенов, кроме устройства.
  • jwt: На основе предыдущего вопроса добавьте количество + 5 и переназначьте устройство на новый счет.

Как отобразить список устройств, на которых зарегистрирован этот пользователь / Как выгнать определенного пользователя

  • сеанс: добавить новое устройство столбца в таблицу токенов
  • jwt: сервер должен хранить информацию о списке устройств, практика такая же, как и в сеансе, использование jwt не имеет смысла.

Суммировать

Из приведенных выше вопросов, если вам не нужно контролировать количество зарегистрированных устройств и информацию об устройстве, jwt без сохранения состояния является хорошим выбором. Как только информация об устройстве задействована, в jwt необходимо добавить дополнительную поддержку состояния, что усложняет аутентификацию.В этом случае сеанс является хорошим выбором.

jwt не является панацеей.Использовать или не использовать jwt нужно решать в соответствии с потребностями бизнеса.