Учебное пособие: простой вход в систему с аутентификацией через API NodeJS и промежуточное ПО с использованием веб-токенов JSON

Требования

  • Узел 6.11.5 или выше

В этом

Начнем с запуска пакетов узлов для этого проекта. Сообщите ему подробности, необходимые для запуска проекта.

npm init

Необходимые пакеты

npm i express --save && npm i bcrypt --save && npm i body-parser --save && npm i jwt-simple --save;

Создать первую конечную точку

Мы собираемся создать нашу первую конечную точку, которая будет просто выводить текущее время в формате UNIX.

ПРИМЕЧАНИЕ. код, отмеченный (-), означает, что код необходимо удалить. Код, отмеченный знаком (+), - это новый код, который необходимо добавить.

/index.js

/* ============================
DEFAULT IMPORTS
============================ */
const express = require('express');
const app = express();
const port = 5000;
/* ============================
ENDPOINTS
============================ */
app.get('/', (req, res) => {
  let dateTime = new Date();

  res.send({
    time: dateTime.getTime()
  });
});
/* ============================
PORT LISTENING
============================ */
app.listen(port);
console.log(`Listening on port ${port}.`);

В Терминальном приложении запустите:

node index.js

По завершении нажмите Ctrl + C.

Перейдите на http: // localhost: 5000 и увидите результат JSON, подобный этому:

{
  time: 1525905645955
}

Создание данных наших пользователей

В качестве учетных данных нашего пользователя мы будем использовать (адрес электронной почты / пароль):

[email protected]
asdf1234

Нам нужно зашифровать пароль нашего пользователя с помощью bcrypt, в приложении терминала выполните:

node
> let bcrypt = require('bcrypt');
> const saltRounds = 10;
> const password = 'asdf1234';
> bcrypt.hash(password, saltRounds, (err, hash) => {
... console.log(hash);
... });

Вы должны увидеть результат:

$2b$10$/ippEcTMPZpZj3fbVJ3jb.0xnT3aAsXaXcska4PV8zSguLqhM5Xw2

Дважды нажмите Ctrl + C, чтобы выйти из узла.

Давайте создадим новый файл users.json, в котором будут храниться следующие данные:

/data/users.json

{
  "users": [
    {
      "id": 1234,
      "email": "[email protected]",
      "password": "$2b$10$/ippEcTMPZpZj3fbVJ3jb.0xnT3aAsXaXcska4PV8zSguLqhM5Xw2"
    }
  ]
}

Теперь давайте импортируем эти данные в наш

/index.js

/* ============================
DEFAULT IMPORTS
============================ */
const express = require('express');
const app = express();
const port = 5000;
+ /* ============================
+ IMPORT MODULES
+ ============================ */
+ const Users = require('./data/users.json');
/* ============================
ENDPOINTS
============================ */
app.get('/', (req, res) => {
  let dateTime = new Date();

  res.send({
    time: dateTime.getTime()
  });
});
/* ============================
PORT LISTENING
============================ */
app.listen(port);
console.log(`Listening on port ${port}.`);

Авторизация входа в конечную точку

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

Для этого нам нужно включить body-parser для обработки полезных данных JSON и создать конечную точку для обработки запроса.

/index.js

/* ============================
DEFAULT IMPORTS
============================ */
const express = require('express');
const app = express();
const port = 5000;
/* ============================
IMPORT MODULES
============================ */
const Users = require('./data/users.json');
+ const bodyParser = require('body-parser');
+ /* ============================
+ CONFIGURATIONS
+ ============================ */
+ app.use(bodyParser.json());
/* ============================
ENDPOINTS
============================ */
app.get('/', (req, res) => {
  let dateTime = new Date();

  res.send({
    time: dateTime.getTime()
  });
});
+ /* ============================
+ ENDPOINTS - AUTH - LOGIN
+ ============================ */
+ app.post('/auth/login', (req, res) => {
+   // validate if payload contains data
+   if (req.body.email && req.body.password) {
+
+     // find the user in the json data
+     let findUser = Users.users.find((user) => {
+       return (user.email === req.body.email) ? user : false
+     });
+
+     if (findUser) {
+       // send data
+       res.send(findUser);
+     } else {
+       res.status(404).send({
+         error: `Could not find user '${req.body.email}'.`
+       });
+     }
+   } else {
+     res.status(401).send({
+       error: `Invalid email and/or password.`
+     });
+   }
+ });
/* ============================
PORT LISTENING
============================ */
app.listen(port);
console.log(`Listening on port ${port}.`);

В Терминальном приложении снова запустите приложение:

node index.js

Давайте запустим приложение Postman, чтобы отправить запрос POST:

Возвращенный результат должен выглядеть примерно так:

{ 
id: 1234,
email: "[email protected]",
password: "$2b$10$/ippEcTMPZpZj3fbVJ3jb.0xnT3aAsXaXcska4PV8zSguLqhM5Xw2"
}

Хорошо, что мы нашли пользователя, но нам нужно еще и подтвердить пароль.

Авторизация Подтвердить пароль

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

/index.js

/* ============================
DEFAULT IMPORTS
============================ */
const express = require('express');
const app = express();
const port = 5000;
/* ============================
IMPORT MODULES
============================ */
+ const bcrypt = require('bcrypt');
const Users = require('./data/users.json');
const bodyParser = require('body-parser');
/* ============================
CONFIGURATIONS
============================ */
app.use(bodyParser.json());
/* ============================
ENDPOINTS
============================ */
app.get('/', (req, res) => {
  let dateTime = new Date();

  res.send({
    time: dateTime.getTime()
  });
});
/* ============================
ENDPOINTS - AUTH - LOGIN
============================ */
app.post('/auth/login', (req, res) => {
  // validate if payload contains data
  if (req.body.email && req.body.password) {

    // find the user in the json data
    let findUser = Users.users.find((user) => {
      return (user.email === req.body.email) ? user : false
    });

    if (findUser) {
+       // compare the encrypted password
+       bcrypt.compare(req.body.password, findUser.password, (err, result) => {
+         if (result === true) {
+           // send data
+           res.send(findUser);
+         } else {
+           res.status(403).send({
+             error: `Invalid email and/or password.`
+           });
+         }
+       });
-      // send data
-      res.send(findUser);
    } else {
      res.status(404).send({
        error: `Could not find user '${req.body.email}'.`
      });
    }
  } else {
    res.status(401).send({
      error: `Invalid email and/or password.`
    });
  }
});
+         } else {
+           res.status(403).send({
+             error: `Invalid email and/or password.`
+           });
+         }
+       });
+
-      // send data
-      res.send(findUser);
    } else {
      res.status(404).send({
        error: `Could not find user '${req.body.email}'.`
      });
    }
  } else {
    res.status(401).send({
      error: `Invalid email and/or password.`
    });
  }
});

В Терминальном приложении снова запустите приложение:

node index.js

Давайте запустим приложение Postman, чтобы отправить POST-запрос с неправильным паролем:

И если мы отправили правильные учетные данные, мы должны получить тот же результат, что и раньше:

{ 
id: 1234,
email: "[email protected]",
password: "$2b$10$/ippEcTMPZpZj3fbVJ3jb.0xnT3aAsXaXcska4PV8zSguLqhM5Xw2"
}

Замечательно, что мы проверяем пароль, но давайте не будем возвращать данные пользователя и пароль, вместо этого предоставив JWT.

Авторизация Создать веб-токен JSON

В следующей части нам нужно добавить jwt-simple, настроить его так, чтобы он содержал секретный токен, и вернуть наш закодированный токен.

/index.js

/* ============================
DEFAULT IMPORTS
============================ */
const express = require('express');
const app = express();
const port = 5000;
/* ============================
IMPORT MODULES
============================ */
+ const jwt = require('jwt-simple');
const bcrypt = require('bcrypt');
const Users = require('./data/users.json');
const bodyParser = require('body-parser');
/* ============================
CONFIGURATIONS
============================ */
app.use(bodyParser.json());
+ app.set('jwtTokenSecret', 'expressjs-api-secret');
/* ============================
ENDPOINTS
============================ */
app.get('/', (req, res) => {
  let dateTime = new Date();
  res.send({
    time: dateTime.getTime()
  });
});
/* ============================
ENDPOINTS - AUTH - LOGIN
============================ */
app.post('/auth/login', (req, res) => {
  // validate if payload contains data
  if (req.body.email && req.body.password) {
    // find the user in the json data
    let findUser = Users.users.find((user) => {
      return (user.email === req.body.email) ? user : false
    });
if (findUser) {
      // compare the encrypted password
      bcrypt.compare(req.body.password, findUser.password, (err, result) => {
        if (result === true) {
-           // send data
-           res.send(findUser);
+           // set token expiration 7 days from now
+           let expiration = new Date();
+           //+ 7 days
+           expiration.setDate(expiration.getDate() + 7); 
+
+           // create JSON web token
+           let token = jwt.encode({
+               iss: findUser.id,
+               email: findUser.email,
+               exp: expiration.getTime()
+            },
+            app.get('jwtTokenSecret')
+           );
+
+           // send data
+           res.send(
+             token: token,
+             expires: expiration
+           });
        } else {
          res.status(403).send({
            error: `Invalid email and/or password.`
          });
        }
      });
    } else {
      res.status(404).send({
        error: `Could not find user '${req.body.email}'.`
      });
    }
  } else {
    res.status(401).send({
      error: `Invalid email and/or password.`
    });
  }
});
/* ============================
PORT LISTENING
============================ */
app.listen(port);
console.log(`Listening on port ${port}.`);

Давайте запустим приложение Postman с правильными учетными данными:

Теперь, когда у нас есть возвращенный токен, нам нужно протестировать, чтобы убедиться, что JWT проверяется через другую конечную точку, которую мы создадим.

Проверить токен с помощью конечной точки

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

/index.js

/* ============================
DEFAULT IMPORTS
============================ */
const express = require('express');
const app = express();
const port = 5000;
/* ============================
IMPORT MODULES
============================ */
const jwt = require('jwt-simple');
const bcrypt = require('bcrypt');
const Users = require('./data/users.json');
const bodyParser = require('body-parser');
+ /* ============================
+ MIDDLEWARE
+ ============================ */
+ const apiMiddleware = (req, res, next) => {
+   // get the header token
+   let token = req.headers['authorization'];
+
+   if (token) {
+     // attempt to decode the token
+     try {
+       let decoded = jwt.decode(token, app.get('jwtTokenSecret'));
+
+       // set value
+       req.user = {
+         id: decoded.iss,
+         email: decoded.email
+       };
+
+       // proceed with next operation
+       next();
+     } catch (err) {
+       res.status(400).send({
+         error: `Invalid or missing token.`
+       });
+     }
+   } else {
+     res.status(401).send({
+       error: `Invalid or missing token.`
+     });
+   }
+ };
+
/* ============================
CONFIGURATIONS
============================ */
app.use(bodyParser.json());
app.set('jwtTokenSecret', 'expressjs-api-secret');
/* ============================
ENDPOINTS
============================ */
app.get('/', (req, res) => {
  let dateTime = new Date();
res.send({
    time: dateTime.getTime()
  });
});
/* ============================
ENDPOINTS - AUTH - LOGIN
============================ */
app.post('/auth/login', (req, res) => {
  // validate if payload contains data
  if (req.body.email && req.body.password) {
// find the user in the json data
    let findUser = Users.users.find((user) => {
      return (user.email === req.body.email) ? user : false
    });
if (findUser) {
      // compare the encrypted password
      bcrypt.compare(req.body.password, findUser.password, (err, result) => {
        if (result === true) {
          // set token expiration 7 days from now
          let expiration = new Date();
          //+ 7 days
          expiration.setDate(expiration.getDate() + 7); 

          // create JSON web token
          let token = jwt.encode({
              iss: findUser.id,
              email: findUser.email,
              exp: expiration.getTime()
           },
           app.get('jwtTokenSecret')
          );
          // send data
          res.send(
            token: token,
            expires: expiration
          });
        } else {
          res.status(403).send({
            error: `Invalid email and/or password.`
          });
        }
      });
    } else {
      res.status(404).send({
        error: `Could not find user '${req.body.email}'.`
      });
    }
  } else {
    res.status(401).send({
      error: `Invalid email and/or password.`
    });
  }
});
+ /* ============================
+ ENDPOINTS - API - USER
+ ============================ */
+ app.get('/users/me', apiMiddleware, (req, res) => {
+   res.send(req.user);
+ });
+
/* ============================
PORT LISTENING
============================ */
app.listen(port);
console.log(`Listening on port ${port}.`);

Теперь, когда мы создали конечную точку для захвата токена заголовка и его проверки, давайте попробуем конечную точку / users / me в приложении Postman без токена:

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

Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOjEyMzQsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImV4cCI6MTUyNjUxMzczMTQ3MH0.AvCf9fIxyj89qaW6UV48xvIxCi5AwqANXth6hhkYMlE

Настройте приложение Postman следующим образом:

Заключение

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

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

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

Код

Если вы хотите проверить измененную версию кода, вы можете клонировать ее здесь: