В наши дни каждый человек имеет встроенную аутентификацию на своих веб-сайтах и в мобильных приложениях. Аутентификация играет огромную роль в области разработки программного обеспечения, и сегодня вы узнаете, как создать REST API аутентификации с помощью Node. Прежде чем мы начнем, убедитесь, что у вас есть следующее.
Предварительные требования
- "Узел"
- Текстовый редактор (я буду использовать VS Code)
- Определение
- Компьютер
- Wi-fi
После того, как у вас есть все вышеперечисленное, вы готовы приступить к работе.
Базовый REST API
Давайте теперь создадим простой REST API в NodeJS, который использует Express. Создайте новый каталог, в котором будет жить наш проект, и запустите следующее:
$ npm init
Пока оставьте все значения по умолчанию, мы можем отредактировать это позже, если нам понадобится.
Теперь, когда мы инициализировали наш проект, нам нужно установить модуль узла express.js:
$ npm install express --save
Это уйдет и получит необходимый модуль экспресс-узла, который мы будем использовать для создания REST API, который мы будем защищать.
Примечание. В данном конкретном примере мы используем Express, но концепции в этом руководстве не зависят от фреймворка и могут использоваться с другими фреймворками веб-приложений, такими как Koa.
Теперь, когда у нас установлены все наши зависимости, мы можем написать код! Создайте новый файл в каталоге вашего проекта с именем index.js
.
index.js
const express = require('express') const app = express() const port = 3000
app.get('/', (req, res) => res.send('Hello World!')) app.listen(port, () => console.log(`Simple Express app listening on port ${port}!`))
Это невероятно простое приложение, которое возвращает Hello World!
всякий раз, когда вы попадаете на путь /
порта 3000
. Впоследствии вы можете запустить это приложение так:
$ node index.js
Example app listening on port 3000!
Теперь, когда это запущено, перейдите к http://localhost:3000/
в своем браузере, и вы увидите, что ваше приложение возвращает вам ожидаемый Hello World!
.
Добавление нескольких конечных точек
Теперь, когда у нас есть базовое приложение NodeJS, работающее на порте 3000, давайте посмотрим, как мы можем его расширить и добавить несколько конечных точек, которые впоследствии можно будет защитить.
Я собираюсь сделать это пока очень простым, чтобы мы могли сосредоточиться на авторизации JWT, а не на базовом приложении.
Откройте ваш index.js
файл еще раз. Давайте добавим несколько новых HTTP GET
конечных точек:
index.js
const express = require('express') const app = express() const port = 3000
app.get('/', (req, res) => res.send('Hello World!'))
// let's first add a /secret api endpoint that we will be protecting app.get('/secret', (req, res) => { res.json({ "message" : "THIS IS SUPER SECRET, DO NOT SHARE!" }) })
// and a /readme endpoint which will be open for the world to see app.get('/readme', (req, res) => { res.json({ "message" : "This is open to the world!" }) })
app.listen(port, () => console.log(`Simple Express app listening on port ${port}!`))
Теперь, когда у нас есть эти конечные точки, давайте повторно запустим наше приложение, чтобы убедиться, что мы ничего не сломали:
$ node index.js
Simple Express app listening on port 3000!
Давайте теперь откроем http://localhost:3000/secret
в окне браузера, когда он запущен. Вы увидите следующий ответ:
http: // localhost: 3000 / secret
{
"message": "THIS IS SUPER SECRET, DO NOT SHARE!"
}
И когда мы откроем конечную точку /readme
, мы должны увидеть следующее:
http: // localhost: 3000 / secret
{
"message": "This is open to the world!"
}
Отлично, на этом шаге мы смогли добавить к нашему приложению 2 дополнительные конечные точки, которые мы попытаемся защитить с помощью проверки JWT на следующем шаге этого руководства.
Создание действительного JWT
На этом этапе мы собираемся создать 1 дополнительную конечную точку для нашего приложения, которая будет возвращать действительный токен JWT, чтобы мы могли протестировать аутентификацию на последующих этапах.
Чтобы сгенерировать и проверить эти JWT, нам нужно сначала импортировать модуль узла jsonwebtoken
:
$ npm install --save jsonwebtoken
После установки этого модуля узла мы можем продолжить и создать пользовательскую конечную точку /jwt
, которая создаст для нас токен JWT, который имеет невероятно простую полезную нагрузку { "body": "stuff" }
и подписан с использованием закрытого ключа, который я сгенерировал для устаревшего проекта.
Создайте в своем проекте новый файл с именем private.pem
и добавьте следующий ключ:
private.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyVTQ9QxfutaYXKBbYfZbH2vhIWoIPEjAFSbsy1PZoIcclUQR
hJ8t2m7v47M8eEyYd7EvXTNdoN6CDs0DoNC9KESATZV5SUVr7sk9pOcMrm0VryAd
h7hQbbHWqyKmOehCt1JdX7gV2i5XnRb5qYQSyoB8sGdfR4SQ9q1XPRIpBP8RYXCP
WPmwnmtzYjfs+VVMp+ByNWgM8Qvyc3Z13tHKHWfTokbEbJJE0xfFG6CVFZy+T7uq
0UxhkWh8tekaDbfrIYtgC8HRHfRPcqvsN/pkJM0DIU4UNIf2TeLARa+iATNiF5IX
DeAAkIqoQL0tgt6S+8HIEPGiQ3gpGE56DON06QIDAQABAoIBAAvIxyJQwxmwjeJ+
EFs/jD3elqLaDflZWMTkLmAIXGik/+tMvKnCl3B9pdTyHMv9z77RxC/0XbqYy4wK
O/ghv7CnscrYwOyk/5hOdyk7zOY4xFgnzRKwmySQkDwcHxasnZsVWxnLMJxAsigj
vCFL9b2cn6/DnTQWclW996k/ct8z5DzodH/O+JyQl2MvLgjtf1OupbNZcjt4kMRP
GS5em5banlycUtPE0NAcS0QXleHLj5BXOp0AyD+PWfzhWcctiK7p+vmwXv6OVtlu
DIiTTOnsjoMq7skfVzRpjmAesllXBb1evwsrVK7cjYefEsVZ5DzOVLNU5Iug3HCf
RnftUAECgYEA6uWhJ9la1VpiYgEai4F61Rxs/MAQzmWVl0NQhPrczLCdRXfhmeBP
w1a4VkCD7FlZq/UuL4bSnU2JINL/enmrfZfdLdQgjY1VgPNki6v4Da9sqi+D17Wb
w863h/X29cukttFgUQdPO66bwsitoNVDsBqyf2hlFWC+rRPovoFA9WkCgYEA22s2
njRgoV6mTTCgXoZMs8unJ2CTd+BuVP1wDVsHR0VnK7blVlIW9Hop0ZmFK3I41kw3
3LXT6RSmZXsdgAsm3VuWlDVFY6t+JUUGYOfZZVNgUX0J597hf2SwxfJ8cgNHuSEO
glxc/dzHXMgamf8+84RCK3NSGP8xmuI/Wm5JE4ECgYEAmFelVTradlTQSc99b8zh
5SUyahoGzFWF1zyJFDW+zeIdndhKMIoSMRYlJ4tgBAFO7v9snNZL8kk/DlLJ7pzK
ZAICKJ7THfrz4VX5d7xofDexug5m65eVFkETNtKHAJK6mPbiCKs87/AmhQWx1gV6
iNRHv+ns5RiBka6/3A3oG0ECgYEAl+qIO0rqaG++1ozHTArSCl4DUlkkYQhLe56p
OSYASRE9WF/eM0DM0eHPGGahdC42OfE1cCOYH7WDa5mtGB0ggHxMKjsj2tk+kpFS
1D9SHjx24JShCiAfonNVjQfRr6KjwwKnKAzI+Z8ljRCikmLN9A5rPegvPE1by++/
i132TIECgYAiDd+OSokfZYi8mqjIoMI946+Hlb7lisb7CXksM69A+oWJrfkCwOMq
O3tExLbxtd7KZuAg1xH2thimIeT6tuCbCSAFGzr4EWCe7iavVzevHr98ivPLYXte
dyWl3YlvqO+SUuieGvHISlekblMO/4tcUscmKmo+FgkMroBsePcdEA==
-----END RSA PRIVATE KEY-----
Затем откройте свой index.js
и добавьте следующее:
index.js
const jwt = require('jsonwebtoken'); const fs = require('fs')
app.get('/jwt', (req, res) => { let privateKey = fs.readFileSync('./private.pem', 'utf8'); let token = jwt.sign({ "body": "stuff" }, "MySuperSecretPassPhrase", { algorithm: 'HS256'}); res.send(token); })
Когда мы открываем http://localhost:3000/jwt
в нашем браузере после перезапуска приложения, мы должны увидеть возвращенный нам действительный веб-токен JSON:
http: // localhost: 3000 / jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJib2R5Ijoic3R1ZmYiLCJpYXQiOjE1NTg4MTUyMzl9.3Z8G-kCEfr2Xch1FnaEAOeywcVs6aJZ3sbCARybWCgM
Замечательно, теперь у нас есть действующий JWT, который мы можем использовать для тестирования аутентификации, которую мы собираемся создать в следующей части этого руководства!
ПО промежуточного слоя аутентификации
Давайте посмотрим на функцию аутентификации, которая будет смотреть на входящий запрос и анализировать его на наличие заголовка Authorization
.
index.js
function isAuthenticated(req, res, next) {
if (typeof req.headers.authorization !== "undefined") {
// retrieve the authorization header and parse out the
// JWT using the split function
let token = req.headers.authorization.split(" ")[1];
let privateKey = fs.readFileSync('./private.pem', 'utf8');
// Here we validate that the JSON Web Token is valid and has been
// created using the same private pass phrase
jwt.verify(token, privateKey, { algorithm: "HS256" }, (err, user) => {
// if there has been an error...
if (err) {
// shut them out!
res.status(500).json({ error: "Not Authorized" });
throw new Error("Not Authorized");
}
// if the JWT is valid, allow them to hit
// the intended endpoint
return next();
});
} else {
// No authorization header exists on the incoming
// request, return not authorized and throw a new error
res.status(500).json({ error: "Not Authorized" });
throw new Error("Not Authorized");
}
}
Теперь, когда у нас есть эта isAuthorized
функция, мы можем обновить нашу /secret
конечную точку, чтобы использовать эту функцию в качестве промежуточного программного обеспечения.
index.js
app.get('/secret', isAuthorized, (req, res) => {
res.json({ "message" : "THIS IS SUPER SECRET, DO NOT SHARE!" })
})
Если мы перезапустим наше приложение и снова попробуем нажать на конечную точку /secret
, мы должны увидеть следующий ответ:
http: // localhost: 3000 / secret
{
"error": "Not Authorized"
}
Отлично, это сработало в точности так, как ожидалось, и мы не можем получить доступ к нашей /secret
конечной точке без соответствующего набора заголовков Authorization
. Давайте попробуем поразить эту конечную точку с помощью команды curl
, мы добавим заголовок Authorization
и установим для него значение jwt
вместе с действительным JWT, полученным с нашей /jwt
конечной точки.
curl -H Авторизация: jwt« http: // localhost: 3000 / secret
{"message":"THIS IS SUPER SECRET, DO NOT SHARE!"}%
Замечательно, с этим допустимым JWT в заголовке Authorization
мы смогли получить доступ к /secret
конечной точке!
Заключение
В этом руководстве нам удалось создать функцию промежуточного программного обеспечения isAuthenticated, с помощью которой мы можем обернуть наши экспресс-конечные точки API. Эта функция `isAuthenticated` анализирует входящие запросы` HTTP`, чтобы проверить, установлен ли у них соответствующий заголовок `Authorization`, а затем проверяет, не значение этого заголовка - действительный токен JWT, подписанный определенным закрытым ключом.
Я задолбался. Что дальше?
На этом веселье не заканчивается, оно продолжается. Вы можете продолжать создавать новые вещи и узнавать что-то новое в других блогах, опубликованных Clever Programmer.
Впереди еще много клонов, советов и многого другого. Я знаю, что ты взволнован и готов, но тебе нужно подождать. Вы также можете проверить канал YouTube, если вас слишком волнует какой-нибудь крутой контент.
Поделитесь этим со всеми, кто, по вашему мнению, получит от этого пользу. Есть предложения? Не стесняйтесь ударить меня!
Увидимся в следующем!
Шрикар Кусуманчи