Hvordan autentisere og autorisere bruker ved å bruke JWT i NodeJS

Autentisering og autorisasjon er det grunnleggende konseptet for datasikkerhet. Du bruker legitimasjonen din (som brukernavn og passord) for å bevise identiteten din og identifisere deg selv som en registrert bruker og deretter få ytterligere privilegier.

Dette gjelder også når du logger på netttjenester ved hjelp av Facebook- eller Google-kontoene dine.

I denne artikkelen skal vi bygge en Nodejs API med JWT (JSON Web Tokens) autentisering. Verktøyene vi skal bruke i denne opplæringen er:

  • Expressjs
  • MongoDB database
  • Mongoose
  • Dotenv
  • Bcryptjs
  • Jsonwebtoken

Autentisering vs. Autorisasjon

Hva er autentisering?

Autentisering er prosessen med å identifisere brukere ved å skaffe seg legitimasjon som e-post, passord og tokens. Den oppgitte legitimasjonen sammenlignes med den registrerte brukerens legitimasjon, som er tilgjengelig i filen til det lokale datasystemet eller eventuelle databaser. Hvis den gitte legitimasjonen samsvarer med tilgjengelige data i databasen, fullføres autentiseringsprosessen, og brukeren får tilgang til ressursene.

Hva er autorisasjon?

Autorisasjon skjer etter autentisering. Hver autorisasjon må ha en autentiseringsprosess. Det er prosessen med å la brukere få tilgang til ressurser fra systemene eller et nettsted. I denne opplæringen vil vi autorisere innloggede brukere til å få tilgang til brukerens data. Hvis brukeren ikke er pålogget, vil de ikke kunne bruke tilgang til dataene.

De beste eksemplene på autorisasjon er sosiale medieplattformer som Facebook og Twitter. Du kan ikke få tilgang til innhold på sosiale medier uten å ha en konto.

Et annet eksempel på autorisasjon er abonnementsbasert innhold, autentiseringen din kan gjøres ved å logge inn på nettstedet, men du vil ikke få tilgang til innholdet før du ikke har abonnert.

Forutsetning

Før du går videre, antar jeg at du har en grunnleggende forståelse av Javascript og MongoDB og god kunnskap om Nodejs.

Sørg for at du har installert node og npm på din lokale maskin. For å sjekke om node og npm er installert på datamaskinen, åpne ledeteksten og skriv node -v og npm -v. Dette skal vise følgende resultat.

Dine versjoner kan avvike fra min. NPM lastes automatisk ned med noden. Hvis du ikke har lastet det ned ennå, last det ned fra NodeJS nettsted.

Du trenger en IDE (integrert utviklingsmiljø) for å skrive kode. I denne opplæringen bruker jeg VS-koderedigering. Hvis du har en annen, kan du bruke den også. Hvis du ikke har noen IDE installert på datamaskinen, kan du laste den ned fra Visual Studio nettsted. Last den ned basert på ditt lokale system.

  Slik kopierer du en mappe i Google Disk

Prosjektoppsett

Lag et mappenavn nodeapi hvor som helst på din lokale datamaskin, og åpne den med vs-code. Åpne vs-code-terminalen og initialiser deretter nodepakkebehandlingen ved å skrive.

npm init -y

Sørg for at du er på nodeapi-katalogen.

Kommandoen ovenfor vil lage en package.json-fil som inneholder alle avhengighetene vi skal bruke i dette prosjektet.

Nå skal vi laste ned alle pakkene nevnt ovenfor, skriv nå inn og skriv dem inn i terminalen.

npm install express dotenv jsonwebtoken mongoose bcryptjs

Nå vil du ha filer og mapper, som vist nedenfor.

Opprette server og koble til database

Lag nå en fil som heter index.js og en mappe som heter config. Inne i config, lag to filer kalt conn.js for å koble til databasen og config.env for å erklære miljøvariabler. Skriv den gitte koden nedenfor i de respektive filene.

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}`);
})

Hvis du bruker dotenv, konfigurer den i index.js-filen din før du kaller opp andre filer som bruker miljøvariabler.

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

Jeg bruker mongo-DB Atlas URI, du kan også bruke localhost.

Lage modeller og ruter

Modell er et oppsett av dataene dine i Mongo-DB-databasen og vil bli lagret som et JSON-dokument. For å lage en modell skal vi bruke mongoose-skjemaet.

Ruting refererer til hvordan en applikasjon svarer på klientforespørsler. Vi vil bruke ekspressruterfunksjonen for å lage ruter.

Rutingmetoder tar vanligvis to argumenter. Den første er rute, og den andre er tilbakeringingsfunksjonen for å definere hva denne ruten vil gjøre på klientens forespørsel.

Det tar også et tredje argument som en mellomvarefunksjon når det er nødvendig, som i autentiseringsprosessen. Ettersom vi bygger autentisert API, vil vi også bruke mellomvarefunksjonen for å autorisere og autentisere brukere.

Nå skal vi lage to mapper kalt ruter og modeller. Inne i ruter oppretter du et filnavn userRoute.js og i models-mappen oppretter du et filnavn userModel.js. Etter å ha opprettet filer, skriv følgende kode i de respektive filene.

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)=>{

})

Implementere rutefunksjonalitet og lage JWT-tokens

Hva er JWT?

JSON web-tokens (JWT) er et javascript-bibliotek som oppretter og verifiserer tokens. Det er en åpen standard som brukes til å dele informasjon mellom to parter – en klient og en server. Vi vil bruke to funksjoner til JWT. Den første funksjonen er tegn for å opprette et nytt token og den andre funksjonen er verifiserer for å bekrefte tokenet.

  Hvordan stille inn en timer i zoom

Hva er bcryptjs?

Bcryptjs er en hashing-funksjon laget av Niels Provos og David Mazières. Den bruker en hash-algoritme for å hash passordet. Den har to vanligste funksjoner som vi skal bruke i dette prosjektet. Den første bcryptjs-funksjonen er hash for å generere hashverdi og den andre funksjonen er sammenligningsfunksjon for å sammenligne passord.

Implementere rutefunksjonalitet

Tilbakeringingsfunksjonen i ruting tar tre argumenter, forespørsel, svar og neste funksjon. Det neste argumentet er valgfritt; pass dette bare når du trenger dette. Disse argumentene skal være i forespørselen, svaret og neste rekkefølge. Endre nå filene userRoute.js, config.env og index.js med følgende koder.

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;

Hvis du bruker Async-funksjonen, bruk try-catch-blokk, ellers vil det gi en uhåndtert løfteavvisningsfeil.

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}`);
})

Opprette mellomvare for å autentisere bruker

Hva er mellomvare?

Mellomvare er en funksjon som har tilgang til forespørselen, svarobjektet og neste funksjon i forespørsel-svar-syklusen. Den neste funksjonen påkalles når funksjonsutførelsen er fullført. Som jeg nevnte ovenfor, bruk next() når du må utføre en annen tilbakeringingsfunksjon eller mellomvarefunksjon.

  Google Camera v2.2-oppdatering gir timer, panoramamoduser og sideforhold

Lag nå en mappe som heter mellomvare, og inni den, lag filnavn som auth.js og skriv følgende kode.

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;

Installer nå cookie-parser-biblioteket for å konfigurere cookieParser i appen din. cookieParser hjelper deg med å få tilgang til tokenet som er lagret i informasjonskapselen. Hvis du ikke har cookieParser konfigurert i nodejs-appen din, vil du ikke kunne få tilgang til informasjonskapslene fra overskriftene til forespørselsobjektet. Skriv nå i terminalen for å laste ned cookie-parser.

npm i cookie-parser

Nå har du en cookieParser installert. Konfigurer appen din ved å endre index.js-filen og legg til mellomvare i «/user/»-ruten.

index.js-filen

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;

Ruten «/bruker» er kun tilgjengelig når brukeren er pålogget.

Sjekker API-ene på POSTMAN

Før du sjekker APIer, må du endre filen package.json. Legg til følgende kodelinjer.

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

Du kan starte serveren ved å skrive npm start, men den vil bare kjøre én gang. For å holde serveren i gang mens du endrer filer, trenger du nodemon. Last den ned ved å skrive inn i terminalen

npm install -g nodemon

-g flagg vil laste ned nodemon globalt på ditt lokale system. Du trenger ikke å laste den ned igjen og igjen for hvert nytt prosjekt.

For å kjøre serveren, skriv inn npm run dev i terminalen. Du vil få følgende resultat.

Til slutt er koden din fullført, og serveren kjører riktig, gå til postmann og sjekk om den fungerer.

Hva er POSTMAN?

POSTMAN er et programvareverktøy for å designe, bygge, utvikle og teste API.

Hvis du ikke har lastet ned postmannen på datamaskinen din, last den ned fra postmann nettsted.

Åpne nå postbudet og lag et samlingsnavn nodeAPItest, og inni det, lag tre forespørsler: register, pålogging og bruker. Du bør ha følgende filer.

Når du sender JSON-data til «localhost:5000/api/register» vil du få følgende resultat.

Ettersom vi oppretter og lagrer tokens i informasjonskapsler under registrering også, kan du få brukerdetaljene når du ber om «localhost:5000/api/user»-ruten. Du kan sjekke resten av forespørslene på POSTMAN.

Hvis du vil ha den komplette koden, kan du få den fra min github-konto.

Konklusjon

I denne opplæringen har vi lært hvordan du bruker autentisering til NodeJS API ved å bruke JWT-tokens. Vi ga også brukere tillatelse til å få tilgang til brukerdataene.

LYKKELIG KODING!