sql >> Databáze >  >> RDS >> Mysql

Jak spravovat relace v Node.js pomocí Passport, Redis a MySQL

HTTP a HTTPS jsou internetové protokoly, které umožňují odesílání dat přes internet odesláním požadavku přes webový prohlížeč. Protože jsou bezstavové, každý požadavek odeslaný do prohlížeče je zpracován nezávisle. To znamená, že prohlížeč si nemůže pamatovat zdroj požadavku, i když jej provede stejný uživatel. Tento problém řeší relace HTTP.

Tento článek se podívá na správu relací a na to, jak nám mohou nástroje jako Passport, Redis a MySQL pomoci spravovat relace Node.js. Pojďme se ponořit.

Jak fungují relace HTTP?

Relace HTTP umožňují webovým serverům udržovat identitu uživatele a ukládat data specifická pro uživatele v rámci více interakcí typu požadavek/odpověď mezi klientskou aplikací a webovou aplikací. Když se klient přihlásí do aplikace, server vygeneruje SessionID. Relace je uložena v paměti pomocí jednoserverového nereplikovaného mechanismu trvalého úložiště. Příklady takových mechanismů zahrnují perzistenci JDBC, perzistenci souborového systému, perzistenci relace založenou na souborech cookie a replikaci v paměti. Když uživatel odešle další požadavek, sessionID je předáno v hlavičce požadavku a prohlížeč zkontroluje, zda se ID shoduje s některým z v úložišti paměti a udělí uživateli přístup, dokud relace nevyprší.

Relace HTTP ukládají do paměti následující data:

  • Specifika relace (identifikátor relace, čas vytvoření, čas posledního přístupu atd.)
  • Kontextové informace o uživateli (například stav přihlášení klienta)

Co je Redis?

Redis (Remote Dictionary Server) je rychlé úložiště dat klíč–hodnota s otevřeným zdrojovým kódem v paměti používané jako databáze, mezipaměť, zprostředkovatel zpráv a fronta.

Redis má doby odezvy menší než milisekundy, což umožňuje miliony požadavků za sekundu pro aplikace v reálném čase v odvětvích, jako jsou hry, reklamní technologie, finance, zdravotnictví a IoT. Výsledkem je, že Redis je nyní jedním z nejpopulárnějších open-source motorů, protože byl pět let po sobě jmenován databází „Most Loved“ Stack Overflow. Díky svému rychlému výkonu je Redis oblíbenou volbou pro ukládání do mezipaměti, správu relací, hraní her, výsledkové tabulky, analýzy v reálném čase, geoprostorové aplikace, propagace jízd, chat/zasílání zpráv, streamování médií a pub/podaplikace.

Co stavíme?

Abychom předvedli správu relací v Node.js, vytvoříme jednoduchou aplikaci pro registraci a přihlášení. Uživatelé se zaregistrují a přihlásí do této aplikace zadáním své e-mailové adresy a hesla. Když se uživatel přihlásí, vytvoří se relace a uloží se do úložiště Redis pro budoucí požadavky. Když se uživatel odhlásí, jeho relaci smažeme. Dost řečí; pojďme začít!

Předpoklady

Tento tutoriál je praktickou ukázkou. Než začnete, ujistěte se, že máte nainstalované následující:

  • Node.js
  • Redis CLI
  • Databáze MySQL
  • Arctype

Kód pro tento tutoriál je k dispozici v mém úložišti Github. Nebojte se klonovat a následovat.

Nastavení projektu

Začněme vytvořením složky projektu pro aplikaci pomocí příkazu níže:

mkdir Session_management && cd Session_management

Poté inicializujte aplikaci Node.js a vytvořte soubor package.json pomocí příkazu níže:

npm init -y

-y flag ve výše uvedeném příkazu říká npm, aby použil výchozí konfiguraci. Nyní vytvořte následující strukturu složek v kořenovém adresáři projektu.

Po vytvoření souboru package.json nainstalujme požadovaný balíček pro tento projekt v další části.

Instalace závislostí

Pro naši aplikaci nainstalujeme následující závislosti:

  • Bcryptjs – Tento modul bude použit k hašování hesla uživatele.
  • Connect-redis - Tento modul poskytne úložiště relací Redis pro Express.
  • Expresní relace - Tento modul bude použit k vytváření relací.
  • Ejs – Tento modul je naším nástrojem pro šablony
  • Pas - Tento modul bude použit pro ověření uživatele
  • Místní pas - Tento modul bude použit pro místní ověření uživatelského jména a hesla
  • Sequelizovat - Tento modul je naším ORM MySQL pro připojení naší aplikace k databázi MySQL.
  • Dotenv - Tento modul bude použit k načtení našich proměnných prostředí.

Pomocí níže uvedeného příkazu nainstalujte všechny požadované závislosti.

npm install bcryptjs connect-redis redis express-session ejs passport passport-local sequelize dotenv

Počkejte na dokončení instalace. Po dokončení instalace pokračujte v nastavení databáze MySQL v další části.

Nastavení databáze MySQL

Pro naši aplikaci vytvoříme databázi MySQL. Předtím však spusťte níže uvedený příkaz a vytvořte uživatelský účet MySQL.

CREATE USER 'newuser'@'localhost' IDENTIFIED BY '1234';

Nyní vytvořte databázi session_db a udělte novému uživateli přístup k databázi pomocí příkazu níže:

#Create database
CREATE DATABASE session_db; 

 #grant access
GRANT ALL PRIVILEGES ON session_db TO 'newuser'@'localhost';

ALTER USER 'newuser'@'localhost' IDENTIFIED WITH mysql_native_password BY '1234';

Nyní znovu načtěte všechna oprávnění pomocí příkazu níže:

FLUSH PRIVILEGES;

S naším nastavením databáze MySQL, pojďme vytvořit naše users databázový model v další části.

Vytvořit expresní server

S nastavením naší databáze MySQL vytvořte expresní server pro naši aplikaci. Otevřete soubor src/server.js a přidejte níže uvedený fragment kódu:

const express = require("express");

const app = express();
const PORT = 4300;


//app middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

//Redis configurations

//Configure session middleware


//Router middleware


app.listen(PORT, () => {
 console.log(`Server started at port ${PORT}`);
});

Ve výše uvedeném fragmentu kódu vytvoříme expresní server, který bude naslouchat požadavkům na portu 4300. Poté pomocí express.json() analyzujeme příchozí požadavky s datovými částmi JSON middleware a analyzovat příchozí požadavky pomocí urlencoded pomocí Express.urlencoded() middleware.

Vytvořte model databáze

V tomto okamžiku je náš expresní server nastaven. Nyní vytvoříme Users model reprezentující uživatelská data, databázi uvidíme pomocí Sequelize . Otevřete soubor src/models/index.js a přidejte fragment kódu níže.

const { Sequelize, DataTypes } = require("sequelize");
const sequelize = new Sequelize({
 host: "localhost",
 database: "session_db",
 username: "newuser",
 password: "1234",
 dialect: "mysql",
});

exports.User = sequelize.define("users", {
 // Model attributes are defined here
 id: {
   type: DataTypes.INTEGER,
   autoIncrement: true,
   primaryKey: true,
 },
 email: {
   type: DataTypes.STRING,
 },
 password: {
   type: DataTypes.STRING,
 },
});

Ve výše uvedeném fragmentu kódu importujeme Sequelize a DateTypes z sequelize pro připojení k naší databázi MySQL a přiřazení datového typu našim vlastnostem modelu. Poté se připojíme k MySQL vytvořením sequelize instance z Sequelize třídy a předání přihlašovacích údajů do naší databáze. Například pomocí sequelize jsme definovali náš model a jeho vlastnosti. Chceme pouze pole ID, e-mail a heslo tohoto výukového programu. Sequelize však vytvoří dvě další pole, createdAt a updatedAt pole.

Nastavte Passport a Redis

Ke zpracování a ukládání přihlašovacích údajů našich uživatelů použijeme a nakonfigurujeme Redis . Chcete-li to provést, otevřete src/index.js soubor a importujte následující závislosti níže:

const session = require("express-session");
const connectRedis = require("connect-redis");
const dotenv = require("dotenv").config()
const { createClient } = require("redis");
const passport = require("passport");

Poté vyhledejte oblast s komentářem //Redis configurations a přidejte fragment kódu níže:

const redisClient = createClient({ legacyMode: true });
redisClient.connect().catch(console.error);
const RedisStore = connectRedis(session);

Ve výše uvedeném úryvku kódu jsme vytvořili připojení k naší databázi, která bude spravovat data uživatelského jména našeho uživatele.

Dále najděte oblast s komentářem //Commented session middleware a přidejte fragment kódu níže:

//Configure session middleware
const SESSION_SECRET = process.env.SESSION_SECRET;

app.use(
 session({
   store: new RedisStore({ client: redisClient }),
   secret: SESSION_SECRET,
   resave: false,
   saveUninitialized: false,
   cookie: {
     secure: false,  // if true only transmit cookie over https
     httpOnly: false, // if true prevent client side JS from reading the cookie
     maxAge: 1000 * 60 * 10, // session max age in milliseconds
   },
 })
);
app.use(passport.initialize());
app.use(passport.session());

Ve výše uvedeném fragmentu kódu jsme vytvořili SESSION_SECRET proměnná v .env soubor pro uchování naší relace v tajnosti, poté jsme vytvořili middleware relace a použili Redis jako náš obchod. Aby relace fungovala, přidáme další dva middleware passport.initialize() a passport.session() .

Vytvořte aplikační řadiče

S naším nastavením Redis a expresní relace vytvoříme trasu pro zpracování informací uživatelů. Chcete-li to provést, otevřete src/controllers/index.js soubor a přidejte níže uvedený fragment kódu:

const { User } = require("../models");
const bcrypt = require("bcrypt");

exports.Signup = async (req, res) => {
 try {
   const { email, password } = req.body;

   //generate hash salt for password
   const salt = await bcrypt.genSalt(12);

   //generate the hashed version of users password
   const hashed_password = await bcrypt.hash(password, salt);

   const user = await User.create({ email, password: hashed_password });
   if (user) {
     res.status(201).json({ message: "new user created!" });
   }
 } catch (e) {
   console.log(e);
 }
};

Ve výše uvedeném fragmentu kódu importujeme bcrypt a náš User destrukujeme email uživatele a password z req.body objekt. Poté jsme heslo zahašovali pomocí bcrypt a vytvořili nového uživatele pomocí sequelize create metoda.

Dále vytvořte home page , registration page , login page s níže uvedeným fragmentem kódu:

exports.HomePage = async (req, res) => {
 if (!req.user) {
   return res.redirect("/");
 }
 res.render("home", {
   sessionID: req.sessionID,
   sessionExpireTime: new Date(req.session.cookie.expires) - new Date(),
   isAuthenticated: req.isAuthenticated(),
   user: req.user,
 });
};

exports.LoginPage = async (req, res) => {
 res.render("auth/login");
};

exports.registerPage = async (req, res) => {
 res.render("auth/register");
};

Na HomePage , vykreslíme některé podrobnosti ověřeného uživatele spolu s home zobrazit.

Nakonec vytvořte logout route, chcete-li odstranit data uživatelského jména uživatele pomocí fragmentu kódu níže:

exports.Logout = (req, res) => {
 req.session.destroy((err) => {
   if (err) {
     return console.log(err);
   }
   res.redirect("/");
 });
};

Vytvořte strategii Passport

V tomto okamžiku se mohou uživatelé zaregistrovat, přihlásit a odhlásit z naší aplikace. Nyní vytvoříme pasovou strategii pro ověření uživatelů a vytvoření relace. Chcete-li to provést, otevřete src/utils/passport.js a přidejte fragment kódu níže:

const LocalStrategy = require("passport-local/lib").Strategy;
const passport = require("passport");
const { User } = require("../models");
const bcrypt = require("bcrypt");

module.exports.passportConfig = () => {
 passport.use(
   new LocalStrategy(
     { usernameField: "email", passwordField: "password" },
     async (email, password, done) => {
       const user = await User.findOne({ where: { email: email } });
       if (!user) {
         return done(null, false, { message: "Invalid credentials.\n" });
       }
       if (!bcrypt.compareSync(password, user.password)) {
         return done(null, false, { message: "Invalid credentials.\n" });
       }
       return done(null, user);

     }
   )
 );

 passport.serializeUser((user, done) => {
   done(null, user.id);
 });

 passport.deserializeUser(async (id, done) => {
   const user = await User.findByPk(id);
   if (!user) {
     done(error, false);
   }
   done(null, user);
 });
};

Do výše uvedeného fragmentu kódu importujeme passport , bcrypt a náš uživatelský model a vytváříme pasový middleware pro použití local-strategy . Poté přejmenujeme výchozí název souboru na názvy polí ( email , password ) používáme k ověřování uživatelů. Nyní zkontrolujeme, zda údaje o uživateli existují v databázi, než pro ně bude možné vytvořit relaci.

Passport.serialize a passport.deserialize příkazy se používají k zachování ID uživatele jako souboru cookie v prohlížeči uživatele a v případě potřeby k načtení ID ze souboru cookie, který se pak použije k získání informací o uživateli při zpětném volání.

done() funkce je interní passport.js funkce, která přebírá ID uživatele jako druhý parametr.

Vytvořte aplikační trasy

S naší pasovou strategií vytvořenou, pojďme pokračovat ve vytváření tras pro naše kontrolory. Chcete-li to provést, otevřete src/routes/index.js soubor a přidejte následující fragment kódu níže:

const express = require("express");
const {
 Signup,
 HomePage,
 LoginPage,
 registerPage,
 Logout,
} = require("../controllers");
const passport = require("passport");

const router = express.Router();

router.route("/").get(LoginPage);
router.route("/register").get(registerPage);
router.route("/home").get(HomePage);
router.route("/api/v1/signin").post(
 passport.authenticate("local", {
   failureRedirect: "/",
   successRedirect: "/home",
 }),
 function (req, res) {}
);
router.route("/api/v1/signup").post(Signup);
router.route("/logout").get(Logout);

module.exports = router;

Ve výše uvedeném úryvku kódu importujeme naše funkce ovladače a vytvoříme pro ně trasu. Pro signin route ,použili jsme passport.authenticate metoda k ověření uživatelů pomocí local strategie v nastavení v předchozí části.

Nyní zpět k našemu server.js vytvoříme middleware pro naše trasy. Předtím musíme importovat náš router a passportConfig funkce.

const router = require("./routes");
const { passportConfig } = require("./utils/passport");

Poté zavoláme passportConfig funkce přímo pod kódem v oblastech s komentářem //Configure session middleware .

passportConfig();

Poté vytvoříme náš middleware trasy hned po zakomentované oblasti//Router middleware .

app.use(router);

Vytvořte naše zobrazení aplikace

S našimi vytvořenými trasami vytvoříme pohledy vykreslené na naší HomePage , LoginPage a RegisterPage ovladače. Předtím nastavíme náš ejs view engine v souboru server.js s úryvkem kódu níže přímo pod oblastí s komentářem //app middleware .

app.set("view engine", "ejs");

Poté začneme na domovské stránce, otevřete views/home.ejs soubor a přidejte následující označení.

<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Document</title>
   <link
     href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
     rel="stylesheet"
     integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
     crossorigin="anonymous"
   />
 </head>

 <body>
   <section>
     <!-- As a heading -->
     <nav class="navbar navbar-light bg-light">
       <div class="container-fluid">
         <a class="navbar-brand">Navbar</a>
         <% if(isAuthenticated){ %>
         <a href="/logout" class="btn btn-danger btn-md">Logout</a>
         <% } %>
       </div>
     </nav>
     <div class="">
       <p class="center">
         Welcome: <b><%= user.email %></b> your sessionID is <b><%= sessionID %></b>
       </p>
       <p>Your session expires in <b><%= sessionExpireTime %></b> seconds</p>
     </div>
   </section>
 </body>
</html>

Zde na naší domovské stránce jsme použili bootstrap k přidání nějakého stylu do našich značek. Poté zkontrolujeme, zda je uživatel ověřen, aby se zobrazilo tlačítko pro odhlášení. Také zobrazujeme Email uživatele , sessionID a ExpirationTime z backendu.

Dále otevřete src/views/auth/resgister a níže přidejte následující označení pro stránku registrace.

<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Document</title>
   <link
     href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
     rel="stylesheet"
     integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
     crossorigin="anonymous"
   />
 </head>
 <body>
   <section class="vh-100" style="background-color: #9a616d">
     <div class="container py-5 h-100">
       <div class="row d-flex justify-content-center align-items-center h-100">
         <div class="col col-xl-10">
           <div class="card" style="border-radius: 1rem">
             <div class="row g-0">
               <div class="col-md-6 col-lg-5 d-none d-md-block">
                 <img
                   src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-login-form/img1.webp"
                   alt="login form"
                   class="img-fluid"
                   style="border-radius: 1rem 0 0 1rem"
                 />
               </div>
               <div class="col-md-6 col-lg-7 d-flex align-items-center">
                 <div class="card-body p-4 p-lg-5 text-black">
                   <form action="api/v1/signup" method="post">
                     <h5
                       class="fw-normal mb-3 pb-3"
                       style="letter-spacing: 1px"
                     >
                       Signup into your account
                     </h5>

                     <div class="form-outline mb-4">
                       <input
                         name="email"
                         type="email"
                         id="form2Example17"
                         class="form-control form-control-lg"
                       />
                       <label class="form-label" for="form2Example17"
                         >Email address</label
                       >
                     </div>

                     <div class="form-outline mb-4">
                       <input
                         name="password"
                         type="password"
                         id="form2Example27"
                         class="form-control form-control-lg"
                       />
                       <label class="form-label" for="form2Example27"
                         >Password</label
                       >
                     </div>

                     <div class="pt-1 mb-4">
                       <button
                         class="btn btn-dark btn-lg btn-block"
                         type="submit"
                       >
                         Register
                       </button>
                     </div>

                     <a class="small text-muted" href="#!">Forgot password?</a>
                     <p class="mb-5 pb-lg-2" style="color: #393f81">
                       Don't have an account?
                       <a href="/" style="color: #393f81">Login here</a>
                     </p>
                     <a href="#!" class="small text-muted">Terms of use.</a>
                     <a href="#!" class="small text-muted">Privacy policy</a>
                   </form>
                 </div>
               </div>
             </div>
           </div>
         </div>
       </div>
     </div>
   </section>
 </body>
</html>

Na stránce registrace jsme vytvořili html formulář pro přijetí údajů o uživatelích. Do formuláře také přidáme atribut active a určíme koncový bod registrace. To znamená, že když uživatel klikne na tlačítko Odeslat, požadavek bude odeslán na adresu /api/v1/signup koncový bod.

Nakonec otevřete soubor src/views/auth/signin.js a níže přidejte následující fragment kódu:

<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Document</title>
   <link
     href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
     rel="stylesheet"
     integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
     crossorigin="anonymous"
   />
 </head>
 <body>
   <section class="vh-100" style="background-color: #9a616d">
     <div class="container py-5 h-100">
       <div class="row d-flex justify-content-center align-items-center h-100">
         <div class="col col-xl-10">
           <div class="card" style="border-radius: 1rem">
             <div class="row g-0">
               <div class="col-md-6 col-lg-5 d-none d-md-block">
                 <img
                   src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-login-form/img1.webp"
                   alt="login form"
                   class="img-fluid"
                   style="border-radius: 1rem 0 0 1rem"
                 />
               </div>
               <div class="col-md-6 col-lg-7 d-flex align-items-center">
                 <div class="card-body p-4 p-lg-5 text-black">
                   <form action="api/v1/signin" method="post">
                     <h5
                       class="fw-normal mb-3 pb-3"
                       style="letter-spacing: 1px"
                     >
                       Sign into your account
                     </h5>

                     <div class="form-outline mb-4">
                       <input
                         name="email"
                         type="email"
                         id="form2Example17"
                         class="form-control form-control-lg"
                       />
                       <label class="form-label" for="form2Example17"
                         >Email address</label
                       >
                     </div>

                     <div class="form-outline mb-4">
                       <input
                         name="password"
                         type="password"
                         id="form2Example27"
                         class="form-control form-control-lg"
                       />
                       <label class="form-label" for="form2Example27"
                         >Password</label
                       >
                     </div>

                     <div class="pt-1 mb-4">
                       <button
                         class="btn btn-dark btn-lg btn-block"
                         type="submit"
                       >
                         Login
                       </button>
                     </div>

                     <a class="small text-muted" href="#!">Forgot password?</a>
                     <p class="mb-5 pb-lg-2" style="color: #393f81">
                       Don't have an account?
                       <a href="/register" style="color: #393f81"
                         >Register here</a
                       >
                     </p>
                     <a href="#!" class="small text-muted">Terms of use.</a>
                     <a href="#!" class="small text-muted">Privacy policy</a>
                   </form>
                 </div>
               </div>
             </div>
           </div>
         </div>
       </div>
     </div>
   </section>
 </body>
</html>

Do výše uvedeného označení jsme přidali html formulář, který bude použit pro přihlášení uživatele odesláním požadavku na /api/v1/signin koncový bod.

Zobrazení dat uživatelů pomocí Arctype

Nyní jsme úspěšně vytvořili aplikaci pro správu relace Node.js. Podívejme se na data uživatelů pomocí Arctype. Chcete-li začít, spusťte Arctype, klikněte na kartu MySQL a zadejte následující přihlašovací údaje MySQL, jak je znázorněno na obrázku níže:

Poté klikněte na users tabulka zobrazí registrované uživatele, jak je znázorněno na níže uvedeném snímku obrazovky:

Závěr

Vytvořením ukázkové přihlašovací aplikace jsme se naučili, jak implementovat správu relací v Node.js pomocí Passport a Redis. Začali jsme představením HTTP relací a jejich fungování, poté jsme se podívali na to, co je Redis, a vytvořili projekt, jak toto vše uvést do praxe. Nyní, když máte znalosti, které hledáte, jak byste ověřili projekty uživatelů?


  1. Jak funguje Tan() v PostgreSQL

  2. Hlášení dat o výkonu SQLDIAG pomocí nástroje RML Utilities Tool | Odstraňování problémů s výkonem serveru SQL -7

  3. Načítání komentářů z PostgreSQL DB

  4. Jak zálohujete a obnovujete databázi jako kopii na stejném serveru?