Рубрики
Без рубрики

Jwt аутентификация в node.js

Хола Амигос! Я узнал о JWT и его применении в node.js, и теперь я рад поделиться своим … Tagged с узлом, JavaScript, JWT, Express.

Хола Амигос!

Я узнал о JWT и его применении в node.js, и теперь я рад поделиться своими знаниями с вами. Надеюсь, вам, ребята, вам нравится читать. В этом посте я расскажу о:

  1. Что именно такое сеть JSON токен
  2. Зачем нам нужен веб -токен JSON
  3. Аутентификация JWT в node.js с Express.js

Согласно официальному сайту JWT:

JSON WEB Токен (JWT) является открытым стандартом ( RFC 7519 ), который определяет компактный и автономный способ надежно передачи информации между сторонами в качестве объекта JSON. Эта информация может быть подтверждена и доверена, потому что она подписана в цифровом виде. JWTS может быть подписан с использованием секрета (с алгоритмом RSA или ECDSA Анкет

Whatttt?

Хорошо! Проще говоря, JWT – это токен, который обеспечивает безопасную передачу данных между одинаковыми или разными веб -серверами.

Но чем он отличается от традиционного сессионного подхода?

Традиционное авторизация пользователя на основе сеансов

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

Json Web Tokens (JWT)

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

Структура JWT

В своей компактной форме токены JSON состоят из трех частей, разделенных точками ( . ), которые:

  • Заголовок
  • Полезная нагрузка
  • Подпись

Поэтому JWT обычно выглядит как следующее.

xxxxx.yyyyy.zzzzz

Ниже приведен образец jwt,

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoX2lkIjoiMzIxNjA1MTA1NDEyQUM2QUVCQzQyOTBERUIxMUJENkEiLCJjbGllbnRfaWQiOiIiLCJjc3JmX3Rva2VuIjoiNHJWMGRuWmpJbEdNOFYrNHN3cFZJQkN0M054SjArYlVkVldTdkNDQUJoaz0iLCJpYXQiOjE2MjA4MzQwNjYsInVzZXJfaWQiOiIyYmJlN2QxMC1hYzYxLTQ2NDItODcyMC04OTI1NGEyYzFhYTgiLCJ1c2VyX3R5cGUiOiJndWVzdF9wYXJlbnQiLCJpc19ndWVzdCI6ZmFsc2V9.FNQFIm0_a7ZA5UeMAlQ1pdKS9r6dbe7ryKU42gT5nPc

Пойдем в jwt.io отладчик, чтобы поиграть с образцом токена JWT, ниже приводится скриншот отладчика.

Если вы видите, есть три части в ключ

  1. Заголовок, имеет информацию в алгоритме и тип токена.

  2. Полезная нагрузка , который содержит претензии. Претензии являются утверждениями о сущности (как правило, пользователю) и дополнительных данных.

    Для получения дополнительной информации о типах претензий, вы можете следовать официальному документу: https://jwt.io/introduction

    Вы, возможно, заметили iat Ключ, который означает выпущено в , как и когда был выпущен этот токен. Это в основном используется для истекающих токенов через определенное количество времени.

  3. Проверка Подпись Эта часть в основном используется для проверки подписи сервером. Нам нужно добавить секретный ключ к этому, чтобы сделать его безопасным.

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

  1. Он хранится на стороне клиента

    Предположим, что есть сервер музыкальных магазинов Yamaha, к которому клиент должен получить доступ, но он может получить доступ к этому серверу только через основной сервер Yamaha. В этом случае, если мы пойдем с:

    a) Традиционный подход, основанный на сеансе, где информация пользователя хранится на уровне сервера, сервер Music Store не будет иметь эту информацию, и пользователь должен будет войти в систему и снова аутентифицировать себя, чтобы получить доступ к Yamaha Music Store. То же самое относится и к серверу магазина моторного хранилища (см. Изображение).

    b) подход на основе JWT, поскольку пользователь хранится на конец клиента, даже после перенаправления с помощью JWT пользователь может запросить сервер Music Store или сервер Motor Store через основной сервер, не выходя из перехода между ними. Одна вещь, которую следует отметить: серверы должны разделить один и тот же секретный ключ среди них, чтобы быть доступными для клиентов при использовании JWT.

  2. Более компактный

    Если мы сравним его с SAML, так как JSON менее словес, чем XML, когда он закодирован, его размер также меньше, что делает JWT более компактным, чем SAML. Это делает JWT хорошим выбором, который будет проходить в средах HTML и HTTP.

  3. Простота использования

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

Теперь давайте попробуем построить простую службу аутентификации JWT в node.js

1. Настраивать

Чтобы продемонстрировать приложение JWT по перекрестному серверу, я буду делать два разных сервера, один для всех запросов, связанных с аутентификацией, и назовите его Authserver.js А вторым будут любые другие запросы API, чтобы получить некоторую информацию с сервера, и мы просто будем назвать Server.js

Authserver.js послушает порт 5000 и Server.js послушает порт 4000

Для начала давайте установим несколько модулей

npm instarm express jsonwebtoken

Примечание : Мы установили Экспресс В качестве структуры в верхней части узла для обработки всех связанных с сервером действий и jsonwebtoken для подписания jwt против пользователя или просто получить JWT для пользователя.

После установки мы просто позвоним в эти модули в обоих наших файлах, т. Е. Authserver.js и Server.js

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

app.use(express.json());

2. Создание JWT в входе в систему

Давайте напишем первый вызов API, который будет Пост Запрос на войти в пользователя в Authserver.js файл.

app.post('/login', (req, res) => {
  // ...
  // Suppose the user authentication is already done

  const username = req.body.username;
  const user = {name: username};

  const accessToken = generateAccessToken(user);
  res.json({accessToken: accessToken});

});

app.listen(5000);

Давайте определим GenerateAccessToken функция, которая в основном вернет JWT

const generateAccessToken = (user) => {
  return jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, {expiresIn: '30s'});
}

Вот определение jwt.sign В

jwt.sign (полезная нагрузка, SenserprivateKey, [Options, Callback])

Обратный вызов может быть двух типов:

  • (Асинхронный) Обратный вызов вызывается с err или JWT.
  • (Синхронный) возвращает JWT как строку.

Примечание : Чтобы использовать переменную среды, нам нужно сначала настроить ее, для которой нам нужно установить другой модуль под названием Dotenv ; Мы установим его с NPM установить Dotenv

После запуска этой команды нам нужно сделать .env Поместите и поместите наш Access_token_secret Там секретный ключ, ценность должна быть чем -то неуязвимым. Например:

“0704d2bf835240faffab848079ce73ccf728ffd833e721afd4d7184845b5fc8f00e9f4e2baa87f9d77432f06f0f0384c736d585dacf3f736d8eda3b740c727dea7291542235fe02d75e6ba755307e2546408cffce0b210b4834ea5eff2587859d101bf94aac0f062036662f279ce6f12d84b890a0eaa357b70a01c6922621591”

Это может быть чем угодно случайным, вы можете генерировать его, запустив следующий скрипт в терминале узла:

require (‘crypto’). randombytes (64) .toString (‘hex’) ;

После помесщения ключа в .env Файл, что нам нужно сделать, это добавить следующую строку в верхней части обоих файлов нашего сервера, чтобы он мог получить доступ Process.env переменные.

require('dotenv').config();

3. Получение данных с сервера

Давайте сделаем запрос GET, чтобы получить некоторые данные с сервера, соответствующего пользователю, соответствующему, в Server.js файл:

const articles = [
  {
    id: 1,
    name: "Atul Kumar",
    title: 'First Article',
  },
  {
    id: 2,
    name: "John Doe",
    title: 'Second Article',
  },
  {
    id: 3,
    name: "Don Joe",
    title: 'Third Article',
  },
];

app.get('/articles', authenticateToken, (req, res) => {
  res.json(articles.filter(article => req.user === article.name));
});

Как вы можете видеть, мы использовали пользовательское промежуточное программное обеспечение AuthenticateTetoken для нашего /статья запрос.

Ниже приведено определение AuthenticateTetoken :

Примечание : Я использовал функцию со стрелкой ES6, поэтому вам нужно написать эту функцию, прежде чем сделать запрос GET.

const authenticateToken = (req, res, next) => {
    // getting the authorization information
  const authHeader = req.headers['authorization'];
    // In our case It's JWT authantication
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) return res.sendStatus(401); // No token found;

    // verify if there is a user corrosponding to the token found in the 
    // authorization header.
  jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
    if (err) return res.sendStatus(403); // The token is there but it's not valid;
        // if the token is valid, i.e the user is present, then in the request we are 
        // attaching the user name, so that it can be used in other action controllers.
    req.user = user.name;
        // proceeding to the next action controller.
    next();
  })
}

Почему мы сделали outheader.split ('') [1]; ?

Поскольку jwt – токен носителя, req.headers ['Authorization']; даст нам строку, имеющую значение, которое будет выглядеть:

"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQXR1bCBLdW1hciIsImlhdCI6MTYyMTAwOTEzMCwiZXhwIjoxNjIxMDA5MTYwfQ.fxDe0Q2S_G5M0qq1Lo91sz2Od9hBS12226Utq0LJ9jY"

Нам просто нужна токеновая часть строки.

Мы в основном проверяем, сделал ли клиент, который сделал Получить запрос на /статьи имеет доступ к этому или нет. Мы делаем это, проверяя, есть ли действительный токен, прикрепленный к запросу. При создании Получить Запрос нам необходимо убедиться, что мы включили JWT в заголовок авторизации.

Но что, если мы этого не сделаем?

Ну, если мы этого не сделаем, то мы получим ‘ Несанкционированный ‘ В органе ответа, потому что, если вы посмотрите на код, код состояния 401 отправляется, когда токен не найден.

Давайте попробуем поиграть с тем, что мы сделали до сих пор, в приложении почтальона.

  1. Давайте попробуем получить доступ к статьям с помощью запроса GET

    1. Без токена носителя:

      Как видите, мы получаем 401 Несанкционированный статус, как мы обсуждали ранее, это потому, что мы вообще не давали токен (вы можете видеть, что поле токена пустое).

    2. С недействительным токеном носителя:

      Мы просто дадим случайный токен JWT, чтобы проверить, что происходит в этом случае.

      На этот раз мы получаем 403 Запрещенный статус, то есть у нас есть токен, но этот токен кажется недействительным.

      Но Atul, как мой жетон может быть недействительным?

      Ну, может быть две причины –

      a) Токен был подделан, или вы, возможно, просто поместили случайную строку для токена.

      b) Токен истек.

      Если вы посмотрите на код, jwt.Verify () Сначала проверяет, является ли этот токен действительным токеном или нет. Если он действителен, он возвращает пользовательский объект. Если это не так, это дает нам статус 403.

      Как мы можем получить доступ к статьям конкретного пользователя?

      Чтобы сделать это, нам нужно сначала войти в систему с пользователем, чтобы можно было создать новый JWT.

  2. Теперь давайте войдем с данным именем пользователя

    Мы попросим /авторизоваться с телом, являющимся объектом JSON, имеющим ключ имя пользователя .

    Мы успешно вошли в систему и получили наши accesstoken (JWT),

    Теперь мы можем использовать это accesstoken В нашем Get /статьи запрос.

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

    Примечание : Мы использовали {истекает: '30s'} как вариант на jwt.sign () Метод, поэтому, если вы попытаетесь получить доступ с тем же AccessToken через 30 секунд, вы получите Запрещенный В ответ, поскольку токен был признан недействительным. Но, как правило, мы не будем ограничивать время истечения до 30 секунд (это был только пример).

Так должен ли пользователь входить снова через каждые 30 секунд, чтобы получить доступ к ее статьям?

Конечно, мы должны были бы добавить еще один вид токена в наше приложение под названием A Обновить токен.

4. Обновить токен

Концепция проста: через каждые 30 секунд мы генерируем новый токен доступа для пользователя с помощью токена обновления пользователя.

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

Давайте оставим это в переменной тогда;

let refreshTokens = [];

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

В нашем .env файл Мы добавим новый секретный ключ Represh_token_secret и назначьте ему некоторое зашифрованное значение, точно так же, как мы сделали для Access_token_secret

Теперь в нашем /вход в систему Контроллер действия мы в основном подтолкнем обновить в Обновления массив, который мы создали.

app.post('/login', (req, res) => {
  // ...
  // Suppose the user authentication is already done

  const username = req.body.username;
  const user = {name: username};

  const accessToken = generateAccessToken(user);
  const refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SECRET)
    // pushing the refreshToken generated for this particular user.
  refreshTokens.push(refreshToken);
  res.json({accessToken: accessToken, refreshToken: refreshToken});

});

Теперь нам нужно будет создать новый запрос POST, чтобы сгенерировать новый токен доступа для конкретного токена обновления в нашем Authserver.js файл

// generates a new access token with the help of the refresh token;
app.post('/token', (req, res) => {
    // getting the token value from the body
  const refreshToken = req.body.token;
  if (!refreshToken) return res.sendStatus(401);
    // if it doesn't belong to the array we created to store all the refreshTokens
    // then return Unauthorized.
  if (!refreshTokens.includes(refreshToken)) return res.sendStatus(403);

  jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
        // if the user is found generate a new access token
    const accessToken = generateAccessToken({ name: user.name});
    res.json({ accessToken: accessToken });
  })
});

Почему мы не передаем объект пользователя непосредственно GenerateAccessToken ?

Это потому, что есть некоторая дополнительная информация, которая хранится в пользовательском объекте, которую мы получаем взамен, следующее – объект пользователя, который мы получаем,

{ name: 'Atul Kumar', iat: 1621086671 }

Проблема в том, что если мы используем весь объект пользователя, jwt.sign () будет генерировать один и тот же AccessToken каждый раз, потому что мы передаем пользовательский объект, имеющий одинаковый IAT

Теперь давайте проверим, работает ли все на почтальоне

  1. Мы войдем в систему и поищем токена доступа и токена обновления в ответе

  2. Мы получим все статьи для этого конкретного пользователя

  3. Теперь, если мы сделаем запрос через 30 секунд с тем же accesstoken Мы получим Запрещено Анкет

  4. Теперь мы генерируем новый токен для этого пользователя, мы сделаем запрос сообщения в /токен Пропустив токен обновления, которые мы получили на первом шаге.

    Мы получим новый accesstoken Анкет

  5. Теперь мы будем использовать этот недавно сгенерированный AccessToken, чтобы снова получить доступ к статьям.

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

Значит ли это, что у пользователей, имеющих токен обновления, будет доступ к приложению навсегда? Могут ли они генерировать новый AccessToken, когда захотят?

Прямо сейчас, да, но мы должны остановить это, а также признав токен обновления. Но Когда подходит подходящее время, чтобы аннулировать токен обновления?

Мы аннулируем токен обновления на /ряд URL Давайте сделаем запрос удаления на это.

5. Аннулировать токен обновления

app.delete('/logout', (req, res) => {
  refreshTokens = refreshTokens.filter(token => token !== req.body.token);
  res.sendStatus(204);
})

Это займет токен обновления в качестве параметра тела, который мы хотели бы освободиться от хранения кэша, или, в нашем случае, массива.

Всякий раз, когда пользователь выходит в систему, обновления в основном истекает (больше не в хранилище). Пользователь должен будет войти снова, чтобы получить свежую пару обновить и accesstoken назначен ей.

Попробуй это:

И теперь мы больше не можем генерировать новые токены доступа, нажимая /токен API, с этим обновить что мы прошли в запросе выхода.

Вот и все на JWT от меня!

Если вы нашли это полезным, есть какие -либо предложения или мысли, чтобы поделиться, дайте мне знать в комментариях ниже:)

Адио до следующей статьи,

Atulkumar: 5000/вход

Оригинал: “https://dev.to/atulkr9/jwt-authentication-in-node-js-1dc6”