Jak ověřit a autorizovat uživatele pomocí JWT v NodeJS

Autentizace a autorizace je základním konceptem počítačové bezpečnosti. Své přihlašovací údaje (jako je uživatelské jméno a heslo) používáte k prokázání své identity a identifikaci jako registrovaného uživatele a poté k získání dalších oprávnění.

To platí také v případě, že se přihlásíte do online služeb pomocí účtu Facebook nebo Google.

V tomto článku se chystáme vytvořit Nodejs API s autentizací JWT (JSON Web Tokens). Nástroje, které budeme v tomto tutoriálu používat, jsou:

  • Expressjs
  • databáze MongoDB
  • Mangusta
  • Dotenv
  • Bcryptjs
  • Jsonwebtoken

Autentizace vs. Povolení

Co je autentizace?

Autentizace je proces identifikace uživatelů získáním přihlašovacích údajů, jako je e-mail, heslo a tokeny. Uvedené přihlašovací údaje jsou porovnávány s přihlašovacími údaji registrovaného uživatele, které jsou k dispozici v souboru lokálního počítačového systému nebo jakýchkoli databází. Pokud se daná pověření shodují s dostupnými údaji v databázi, proces ověřování je dokončen a uživateli je povolen přístup ke zdrojům.

Co je autorizace?

Autorizace probíhá po ověření. Každá autorizace musí mít autentizační proces. Je to proces umožňující uživatelům přístup ke zdrojům ze systémů nebo webových stránek. V tomto tutoriálu budeme autorizovat přihlášené uživatele k přístupu k datům uživatele. Pokud uživatel není přihlášen, nebude mít přístup k datům.

Nejlepšími příklady autorizace jsou platformy sociálních médií jako Facebook a Twitter. Bez účtu nemáte přístup k obsahu sociálních sítí.

Dalším příkladem autorizace je obsah založený na předplatném, vaše ověření lze provést přihlášením na webovou stránku, ale nebudete mít oprávnění k přístupu k obsahu, dokud se nepřihlásíte k odběru.

Předpoklad

Než se pohnete vpřed, předpokládám, že máte základní znalosti Javascriptu a MongoDB a dobré znalosti Nodejs.

Ujistěte se, že jste na místní počítač nainstalovali node a npm. Chcete-li zkontrolovat, zda jsou na vašem počítači nainstalovány node a npm, otevřete příkazový řádek a zadejte node -v a npm -v. To by mělo ukázat následující výsledek.

Vaše verze se mohou lišit od mých. NPM se automaticky stáhne s uzlem. Pokud jste si ji ještě nestáhli, stáhněte si ji z Web NodeJS.

K psaní kódu budete potřebovat IDE (Integrované vývojové prostředí). V tomto tutoriálu používám editor kódu VS. Pokud máte jinou, můžete ji také použít. Pokud nemáte na svém počítači nainstalované žádné IDE, můžete si jej stáhnout z Web Visual Studio. Stáhněte si ji na základě vašeho místního systému.

Nastavení projektu

Vytvořte složku s názvem nodeapi kdekoli v místním počítači a poté ji otevřete pomocí vs-code. Otevřete terminál vs-code a poté inicializujte správce balíčků uzlů zadáním.

npm init -y

Ujistěte se, že jste v adresáři nodeapi.

  8 úžasných motivů Mate ke stažení

Výše uvedený příkaz vytvoří soubor package.json, který obsahuje všechny závislosti, které budeme v tomto projektu používat.

Nyní stáhneme všechny výše zmíněné balíčky, nyní je zadejte a zadejte do terminálu.

npm install express dotenv jsonwebtoken mongoose bcryptjs

Nyní budete mít soubory a složky, jak je znázorněno níže.

Vytvoření serveru a připojení databáze

Nyní vytvořte soubor s názvem index.js a složku s názvem config. Uvnitř config vytvořte dva soubory s názvem conn.js pro připojení k databázi a config.env pro deklaraci proměnných prostředí. Níže uvedený kód napište do příslušných souborů.

index.js

const express = require('express');
const dotenv = require('dotenv');

//Configure dotenv files above using any other library and files
dotenv.config({path:'./config/config.env'}); 

//Creating an app from express
const app = express();

//Using express.json to get request of json data
app.use(express.json());



//listening to the server
app.listen(process.env.PORT,()=>{
    console.log(`Server is listening at ${process.env.PORT}`);
})

Pokud používáte dotenv, nakonfigurujte jej v souboru index.js před voláním dalších souborů, které používají proměnné prostředí.

conn.js

const mongoose = require('mongoose');

mongoose.connect(process.env.URI, 
    { useNewUrlParser: true,
     useUnifiedTopology: true })
    .then((data) => {
        console.log(`Database connected to ${data.connection.host}`)
})

config.env

URI = 'mongodb+srv://ghulamrabbani883:[email protected]/?retryWrites=true&w=majority'
PORT = 5000

Používám mongo-DB Atlas URI, můžete také použít localhost.

Vytváření modelů a tras

Model je rozložení vašich dat v databázi Mongo-DB a bude uloženo jako dokument JSON. K vytvoření modelu použijeme schéma mongoose.

Směrování se týká toho, jak aplikace reaguje na požadavky klientů. K vytváření tras použijeme funkci expresního routeru.

Metody směrování obvykle používají dva argumenty. První je trasa a druhá je funkce zpětného volání, která definuje, co by tato trasa udělala na žádost klienta.

V případě potřeby bere také třetí argument jako funkci middlewaru, například v procesu ověřování. Při vytváření autentizovaného API budeme také používat funkci middlewaru k autorizaci a ověřování uživatelů.

Nyní vytvoříme dvě složky s názvem trasy a modely. Uvnitř tras vytvořte název souboru userRoute.js a uvnitř složky modelů vytvořte název souboru userModel.js. Po vytvoření souborů zapište do příslušných souborů následující kód.

userModel.js

const mongoose = require('mongoose');

//Creating Schema using mongoose
const userSchema = new mongoose.Schema({
    name: {
        type:String,
        required:true,
        minLength:[4,'Name should be minimum of 4 characters']
    },
    email:{
        type:String,
        required:true,
        unique:true,
    },
    password:{
        type:String,
        required:true,
        minLength:[8,'Password should be minimum of 8 characters']
    },
    token:{
        type:String
    }
})

//Creating models
const userModel = mongoose.model('user',userSchema);
module.exports = userModel;

userRoute.js

const express = require('express');
//Creating express router
const route = express.Router();
//Importing userModel
const userModel = require('../models/userModel');

//Creating register route
route.post('/register',(req,res)=>{

})
//Creating login routes
route.post('/login',(req,res)=>{

})

//Creating user routes to fetch users data
route.get('/user',(req,res)=>{

})

Implementace funkčnosti trasy a vytváření tokenů JWT

Co je JWT?

JSON webové tokeny (JWT) je javascriptová knihovna, která vytváří a ověřuje tokeny. Jedná se o otevřený standard používaný ke sdílení informací mezi dvěma stranami – klientem a serverem. Využijeme dvě funkce JWT. První funkcí je podepsat pro vytvoření nového tokenu a druhou funkcí je ověření pro ověření tokenu.

Co je bcryptjs?

Bcryptjs je hašovací funkce vytvořená Nielsem Provosem a Davidem Mazièresem. K hašování hesla používá hašovací algoritmus. Má dvě nejběžnější funkce, které budeme v tomto projektu používat. První funkce bcryptjs je hash pro generování hodnoty hash a druhá funkce je funkce porovnání pro porovnání hesel.

  Jak skrýt náhledy zpráv Slack na uzamčené obrazovce

Implementujte funkcionalitu trasy

Funkce zpětného volání ve směrování přebírá tři argumenty, požadavek, odpověď a další funkci. Další argument je volitelný; předávejte to, jen když to potřebujete. Tyto argumenty by měly být v požadavku, odpovědi a dalším pořadí. Nyní upravte soubory userRoute.js, config.env a index.js pomocí následujících kódů.

userRoute.js

//Requiring all the necessary files and libraries
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

//Creating express router
const route = express.Router();
//Importing userModel
const userModel = require('../models/userModel');

//Creating register route
route.post("/register", async (req, res) => {

    try {
        const { name, email, password } = req.body;
        //Check emptyness of the incoming data
        if (!name || !email || !password) {
            return res.json({ message: 'Please enter all the details' })
        }

        //Check if the user already exist or not
        const userExist = await userModel.findOne({ email: req.body.email });
        if (userExist) {
            return res.json({ message: 'User already exist with the given emailId' })
        }
        //Hash the password
        const salt = await bcrypt.genSalt(10);
        const hashPassword = await bcrypt.hash(req.body.password, salt);
        req.body.password = hashPassword;
        const user = new userModel(req.body);
        await user.save();
        const token = await jwt.sign({ id: user._id }, process.env.SECRET_KEY, {
            expiresIn: process.env.JWT_EXPIRE,
        });
        return res.cookie({ 'token': token }).json({ success: true, message: 'User registered successfully', data: user })
    } catch (error) {
        return res.json({ error: error });
    }

})
//Creating login routes
route.post('/login', async (req, res) => {
    try {
        const { email, password } = req.body;
        //Check emptyness of the incoming data
        if (!email || !password) {
            return res.json({ message: 'Please enter all the details' })
        }
        //Check if the user already exist or not
        const userExist = await userModel.findOne({email:req.body.email});
        if(!userExist){
            return res.json({message:'Wrong credentials'})
        }
        //Check password match
        const isPasswordMatched = await bcrypt.compare(password,userExist.password);
        if(!isPasswordMatched){
            return res.json({message:'Wrong credentials pass'});
        }
        const token = await jwt.sign({ id: userExist._id }, process.env.SECRET_KEY, {
            expiresIn: process.env.JWT_EXPIRE,
        });
        return res.cookie({"token":token}).json({success:true,message:'LoggedIn Successfully'})
    } catch (error) {
        return res.json({ error: error });
    }

})

//Creating user routes to fetch users data
route.get('/user', async (req, res) => {
    try {
        const user  = await userModel.find();
        if(!user){
            return res.json({message:'No user found'})
        }
        return res.json({user:user})
    } catch (error) {
        return res.json({ error: error });  
    }
})

module.exports = route;

Pokud používáte funkci Async, použijte blok try-catch, jinak vyvolá neošetřenou chybu odmítnutí slibu.

config.env

URI = 'mongodb+srv://ghulamrabbani883:[email protected]/?retryWrites=true&w=majority'
PORT = 5000
SECRET_KEY = KGGK>HKHVHJVKBKJKJBKBKHKBMKHB
JWT_EXPIRE = 2d

index.js

const express = require('express');
const dotenv = require('dotenv');

//Configure dotenv files above using any other library and files
dotenv.config({path:'./config/config.env'}); 
require('./config/conn');
//Creating an app from express
const app = express();
const route = require('./routes/userRoute');

//Using express.json to get request of json data
app.use(express.json());
//Using routes

app.use('/api', route);

//listening to the server
app.listen(process.env.PORT,()=>{
    console.log(`Server is listening at ${process.env.PORT}`);
})

Vytváření middlewaru pro ověření uživatele

Co je middleware?

Middleware je funkce, která má přístup k požadavku, objektu odezvy a další funkci v cyklu požadavek-odpověď. Další funkce je vyvolána po dokončení provádění funkce. Jak jsem zmínil výše, použijte next(), když musíte provést jinou funkci zpětného volání nebo middlewarovou funkci.

  Jak přiblížit Nintendo Switch při hraní jakékoli hry

Nyní vytvořte složku s názvem middleware a v ní vytvořte název souboru jako auth.js a napište následující kód.

auth.js

const userModel = require('../models/userModel');
const jwt = require('jsonwebtoken');
const isAuthenticated = async (req,res,next)=>{
    try {
        const {token} = req.cookies;
        if(!token){
            return next('Please login to access the data');
        }
        const verify = await jwt.verify(token,process.env.SECRET_KEY);
        req.user = await userModel.findById(verify.id);
        next();
    } catch (error) {
       return next(error); 
    }
}

module.exports = isAuthenticated;

Nyní nainstalujte knihovnu cookie-parser, abyste nakonfigurovali cookieParser ve vaší aplikaci. cookieParser vám pomůže získat přístup k tokenu uloženému v cookie. Pokud nemáte v aplikaci nodejs nakonfigurovaný cookieParser, nebudete mít přístup k souborům cookie ze záhlaví objektu požadavku. Nyní napište do terminálu a stáhněte si analyzátor souborů cookie.

npm i cookie-parser

Nyní máte nainstalovaný cookieParser. Nakonfigurujte svou aplikaci úpravou souboru index.js a přidáním middlewaru do trasy „/user/“.

soubor index.js

const cookieParser = require('cookie-parser');
const express = require('express');
const dotenv = require('dotenv');

//Configure dotenv files above using any other library and files
dotenv.config({path:'./config/config.env'}); 
require('./config/conn');
//Creating an app from express
const app = express();
const route = require('./routes/userRoute');

//Using express.json to get request of json data
app.use(express.json());
//Configuring cookie-parser
app.use(cookieParser()); 

//Using routes
app.use('/api', route);

//listening to the server
app.listen(process.env.PORT,()=>{
    console.log(`Server is listening at ${process.env.PORT}`);
})

userRoute.js

//Requiring all the necessary files and libraries
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const isAuthenticated = require('../middleware/auth');

//Creating express router
const route = express.Router();
//Importing userModel
const userModel = require('../models/userModel');

//Creating user routes to fetch users data
route.get('/user', isAuthenticated, async (req, res) => {
    try {
        const user = await userModel.find();
        if (!user) {
            return res.json({ message: 'No user found' })
        }
        return res.json({ user: user })
    } catch (error) {
        return res.json({ error: error });
    }
})

module.exports = route;

Cesta „/user“ je přístupná pouze tehdy, když je uživatel přihlášen.

Kontrola API na POSTMAN

Než zkontrolujete rozhraní API, musíte upravit soubor package.json. Přidejte následující řádky kódu.

"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "node index.js",
    "dev": "nodemon index.js"
  },

Server můžete spustit zadáním npm start, ale spustí se pouze jednou. Chcete-li udržet váš server v chodu při změně souborů, budete potřebovat nodemon. Stáhněte si jej zadáním do terminálu

npm install -g nodemon

-g příznak stáhne uzlu globálně na váš lokální systém. Nemusíte jej stahovat znovu a znovu pro každý nový projekt.

Chcete-li spustit server, zadejte do terminálu npm run dev. Získáte následující výsledek.

Nakonec je váš kód dokončen a server běží správně, přejděte k pošťákovi a zkontrolujte, zda funguje.

Co je POSTMAN?

POSTMAN je softwarový nástroj pro návrh, sestavení, vývoj a testování API.

Pokud jste si pošťáka nestáhli do počítače, stáhněte si ho z web pošťáka.

Nyní otevřete pošťáka a vytvořte název kolekce nodeAPItest a v něm vytvořte tři požadavky: registraci, přihlášení a uživatele. Měli byste mít následující soubory.

Když odešlete data JSON na „localhost:5000/api/register“, získáte následující výsledek.

Vzhledem k tomu, že vytváříme a ukládáme tokeny do souborů cookie také během registrace, můžete mít údaje o uživateli, když požadujete cestu „localhost:5000/api/user“. Zbytek požadavků si můžete zkontrolovat na POSTMAN.

Pokud chcete úplný kód, můžete ho získat od mého účet github.

Závěr

V tomto tutoriálu jsme se naučili, jak aplikovat ověřování na NodeJS API pomocí tokenů JWT. Také jsme povolili uživatelům přístup k uživatelským údajům.

ŠŤASTNÉ KÓDOVÁNÍ!