Как добавить аутентификацию в полнофункциональное веб-приложение MERN
9 ноября 2022 г.Эта статья является частью 2 раздела "Давайте создадим и развернем полное стек веб-приложения MERN". В этом руководстве мы создали приложение под названием Productivity Tracker, которое позволяет вам вести журнал своей повседневной деятельности. Однако есть проблема с нашим приложением. Сможете разобраться 👀? Ваша подсказка в названии этой статьи. В этом руководстве мы рассмотрим проблему и способы ее решения.
Начнем
Проблема
Поскольку ваше приложение в настоящее время доступно в Интернете, любой может использовать его и добавлять действия в вашу базу данных. Это нехорошо, не так ли? Здесь на помощь приходит аутентификация. Чтобы предотвратить несанкционированный доступ к вашему приложению, добавьте аутентификацию.
Добавление аутентификации
Нам пришлось разрабатывать внешнюю и внутреннюю аутентификацию отдельно, потому что мы разделили их. Еще раз, для простоты, мы создадим базовую аутентификацию без использования каких-либо библиотек.
Внутренняя аутентификация
Нам нужно внедрить внутреннюю аутентификацию и авторизовать некоторые маршруты.
Аутентификация и авторизация
Эти два слова могут сбить вас с толку. Аутентификация позволяет кому-то с учетными данными получить доступ к нашему приложению, а Авторизация предоставляет доступ к ресурсам авторизованным людям.
В нашем сценарии авторизация предоставляет доступ к таким ресурсам, как создание действий и получение действий, тогда как проверка подлинности предполагает вход в приложение.
Введение в JWT
<цитата>Веб-токен JSON (JWT) – это компактное безопасное для URL средство представления заявок, которые должны быть переданы между двумя сторонами. Утверждения в JWT кодируются как объект JSON, который используется в качестве полезной нагрузки структуры веб-подписи JSON (JWS) или в качестве открытого текста структуры веб-шифрования JSON (JWE), что позволяет утверждениям быть подписанными в цифровом виде или защищенными от нарушения целостности. с кодом аутентификации сообщения (MAC) и/или в зашифрованном виде.
Проще говоря, JWT используется для проверки наличия у пользователя разрешения на выполнение действия.
Давайте реализуем аутентификацию при входе с помощью JWT.
Поскольку вы единственный человек, использующий ваше приложение, вам не нужна функция регистрации, и вы можете хранить EMAIL
и PASSWORD
в файле .env
. .
* Откройте файл .env
и добавьте эти три переменные.
TOKEN_KEY=somesecrettoken
EMAIL=youremail
PASSWORD=yourpassword
Здесь TOKEN_KEY
может быть любой случайной строкой. Он используется JWT.
- Откройте терминал и установите пакет
jsonwebtoken
.
npm i jsonwebtoken
- Откройте папку
controllers
и создайте файлauth.controller.js
. Скопируйте и вставьте приведенный ниже код.
const jwt = require("jsonwebtoken");
require("dotenv").config();
const EMAIL = process.env.EMAIL;
const PASSWORD = process.env.PASSWORD;
/* If the email and password are correct, then return a token. */
const login = (req, res) => {
/* Destructuring the email and password from the request body. */
const { email, password } = req.body;
if (email === EMAIL && password === PASSWORD) {
/* Creating a token. */
const token = jwt.sign({ email }, process.env.TOKEN_KEY, {
expiresIn: "2h",
});
return res.status(200).json({
statusCode: 200,
msg: "Login successful",
token,
});
}
return res.status(401).json({
statusCode: 401,
msg: "Invalid Credentials",
});
};
module.exports = {
login,
};
Приведенный выше код проверяет, совпадают ли адрес электронной почты и пароль, и если они совпадают, он создает токен и отправляет его во внешний интерфейс для реализации внешней аутентификации.
- Откройте папку
routes
, создайтеauth.routes.js
и зарегистрируйте новый маршрут для входа в систему.
const express = require("express");
const { login } = require("../controllers/auth.controller");
const router = express.Router();
router.post("/login", login);
module.exports = router;
- Наконец, в
server.js
используйте зарегистрированный маршрут.
...
const AuthRouter = require("./routes/auth.route");
...
...
app.use("/api/auth", AuthRouter);
...
Мы успешно внедрили аутентификацию. Теперь только аутентифицированные люди могут получить доступ к нашему приложению. Но люди, прошедшие проверку подлинности, по-прежнему могут получать доступ к нашим ресурсам и добавлять действия, поскольку мы не авторизовали эти маршруты.
Давайте создадим промежуточное ПО для авторизации этих маршрутов.
GET /api/activities
POST /api/activity
- В корне проекта создайте папку с именем
middleware
, а в этой папке создайте файлauth.js
. Скопируйте и вставьте приведенный ниже код.
const jwt = require("jsonwebtoken");
require("dotenv").config();
/* It checks if the token is valid and if it is, it decodes it and attaches the decoded token to the request object */
const verifyToken = (req, res, next) => {
const token = String(req.headers.authorization)
.replace(/^bearer|^jwt/i, "")
.replace(/^s+|s+$/gi, "");
try {
if (!token) {
return res.status(403).json({
statusCode: 403,
msg: "A token is required for authentication",
});
}
/* Verifying the token. */
const decoded = jwt.verify(token, process.env.TOKEN_KEY);
req.userData = decoded;
} catch (err) {
return res.status(401).json({
statusCode: 401,
msg: "Invalid Token",
});
}
return next();
};
module.exports = verifyToken;
Мы создали промежуточную функцию под названием verifyToken()
для проверки токена, отправленного внешним интерфейсом через заголовок. Если проверка прошла успешно, пользователь может получить доступ к вышеуказанным маршрутам.
- Теперь откройте
activity.route.js
и измените код следующим образом.
...
router.get("/activities", auth, getActivities);
router.post("/activity", auth, addActivity);
...
Вот оно! Внутренняя аутентификация выполнена 🎉.
Внешняя аутентификация
Пришло время реализовать внешнюю аутентификацию.
- Сначала создадим страницу входа.
- В папке
src
создайте файлыLogin.jsx
иLogin.css
. Скопируйте и вставьте приведенный ниже код в файлLogin.jsx
и используйте это вLogin.css
.
```javascript! импортировать React из «реагировать»;
импортировать "./Login.css";
постоянный логин = () => { / Когда пользователь отправляет форму, предотвратить действие по умолчанию, получить адрес электронной почты и пароль из формы, отправить запрос POST на серверную часть с адресом электронной почты и паролем и, если ответ будет успешным, сохранить токен в локальном хранилище и перезагрузите страницу. / const handleSubmit = async (событие) => { событие.preventDefault(); const {адрес электронной почты, пароль} = event.target;
const response = await fetch(
`${process.env.REACT_APP_BACKEND_URL}/auth/login`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email.value,
password: password.value,
}),
}
);
const data = await response.json();
localStorage.setItem("token", data.token);
window.location.reload();
};
возврат (
Войти
экспортировать логин по умолчанию;
This will render the login page.
![login page](https://cdn.hackernoon.com/images/5L1PsURyndeLVm1wIoUdHEN6ZP12-2022-11-08T19:29:01.285Z-cla8lvip1002n0bs6hosu0nht)
The `handleSubmit()` gets the email and password from the form, makes a `POST` request, and sends email and password values for verification. After that server verifies and sends back a token that we can use to access resources.
Here we are using `localStorage` to store the value in the browser permanently so that we won't get logged out after closing the application or browser.
* Open the `index.js` file and add this logic. If there is a token in `localStorage` render `App.jsx` otherwise `Login.jsx`.
```javascript
...
const token = localStorage?.getItem("token");
root.render(
<React.StrictMode>
{token ? <App /> : <Login />}
</React.StrictMode>
);
...
- Теперь в файле
App.jsx
нам нужно отправитьтокен
через заголовок, чтобы серверная часть проверила его и предоставила доступ к маршрутам.
...
useEffect(() => {
const fetchData = async () => {
const result = await fetch(
`${process.env.REACT_APP_BACKEND_URL}/activities`,
{
headers: {
Authorization: `Bearer ${token}`, // <----------- HERE
},
}
);
const data = await result.json();
setActivities(data);
};
fetchData();
}, [token]);
...
...
const addActivity = async (event) => {
event.preventDefault();
const newActivity = {
name: event.target.activity.value,
time: event.target.time.value,
};
await fetch(`${process.env.REACT_APP_BACKEND_URL}/activity`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`, // <---------- HERE
},
body: JSON.stringify(newActivity),
});
event.target.activity.value = "";
event.target.time.value = "";
window.location.reload();
};
...
Готово ✅! Мы внедрили как внешнюю, так и внутреннюю аутентификацию. Теперь только вы можете получить доступ к своему приложению 🥳 (если вы не поделитесь своими учетными данными 👀).
Исходный код: productivity-app
В следующей статье мы научимся писать тесты для фронтенда и бэкенда 😍.
Также здесь
Оригинал