Օգտագործողի նույնականացում NodeJS-ում Passport-ի և MongoDB-ի միջոցով


Օգտագործողի նույնականացումը կարևոր է զգայուն տեղեկատվության պաշտպանության համար: Բարեբախտաբար, դա իրականացնելը դժվար չէ:

Եթե ցանկանում եք պաշտպանել զգայուն բովանդակությունը ձեր Node հավելվածում, ձեզ անհրաժեշտ է օգտատերերին իսկությունը հաստատելու միջոց: Այնուամենայնիվ, նույնականացման ձեր սեփական համակարգի կառուցումը բարդ է և ժամանակատար, և եթե այն ճիշտ չկատարվի, կարող է անվտանգության խոցելիություններ առաջացնել ձեր հավելվածում: Երրորդ կողմի գործիքները, ինչպիսիք են Passport-ը, հեշտացնում են նույնականացումը:

Այս ձեռնարկում դուք կսովորեք, թե ինչպես իրականացնել նույնականացում Node-ում՝ օգտագործելով Passport-ը և MongoDB-ը:

Որո՞նք են նույնականացումը և թույլտվությունը:

Թեև իսկությունը և թույլտվությունը երբեմն օգտագործվում են փոխադարձաբար, անվտանգության այս երկու հասկացությունները տարբեր իմաստներ ունեն: Նույնականացումն այն գործընթացն է, որը թույլ է տալիս ստուգել, որ օգտատերը, թե ով է նրանք պնդում, թե ով է, մինչդեռ թույլտվությունը որոշում է, թե արդյոք վավերացված օգտատերը մուտք ունի ձեր հավելվածի որոշ մասեր:

Ի՞նչ է Passport.js-ը:

Passport.js-ը (կամ Passport-ը) նույնականացման միջին ծրագիր է NodeJS-ի համար, որն ապահովում է ավելի քան 500 ռազմավարություն օգտատերերի նույնականացման համար, ներառյալ passport-local, որն օգտագործում է օգտանուն և գաղտնաբառ:

Այս ձեռնարկը օգտագործում է passport-local ևpasport-jwt՝ երթուղիները պաշտպանելու համար:

Ինչպես կարգավորել օգտվողի նույնականացումը NodeJS-ում

Այժմ դուք մի փոքր գիտեք օգտվողի նույնականացման և Passport.js-ի մասին, մենք կարող ենք տեսնել, թե ինչպես կարելի է նույնականացումը կարգավորել NodeJS-ում: Ստորև մենք նախանշել ենք այն քայլերը, որոնք դուք պետք է կատարեք:

Քայլ 1. Ստեղծեք հանգույցի սերվեր

Ստեղծեք թղթապանակ user-auth-nodejs և նավարկեք դեպի այն՝ օգտագործելով ձեր տերմինալը:

mkdir user-auth-nodejs

cd user-auth-nodejs

Հաջորդ սկզբնավորելpack.json.

npm init

Քանի որ դուք կօգտագործեք Express-ը՝ NodeJS backend-ի շրջանակը, տեղադրեք այն՝ գործարկելով հետևյալ հրամանը։

npm i express

Այժմ ստեղծեք ֆայլ՝app.js և ավելացրեք հետևյալ կոդը՝ սերվերը ստեղծելու համար:

const express = require("express");
const app = express();
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});

Քայլ 2. Ստեղծեք տվյալների բազան

Օգտագործողի տվյալները պահելու համար ձեզ անհրաժեշտ է տվյալների բազա: Դուք կօգտագործեք mongoose-ը MongoDB տվյալների սխեման ստեղծելու համար, որը սահմանում է տվյալների կառուցվածքը և տեսակը, որը դուք կպահեք տվյալների բազայում: Քանի որ դուք պահպանում եք օգտվողի տվյալները, ստեղծեք օգտվողի սխեման:

Տեղադրեք մանգուստ:

npm i mongoose

Ստեղծեք նոր ֆայլ՝userModel.js և ավելացրեք հետևյալը։

const mongoose = require('mongoose')
const {Schema} = mongoose
const UserSchema = new Schema ({
   email: {
       type: String,
       required: true
   },
   password: {
       type: String,
       required: true
   }
})
const UserModel = mongoose.model('user', UserSchema);
module.exports = UserModel;

Նախքան գաղտնաբառը պահելը, դուք պետք է գաղտնագրեք այն անվտանգության նկատառումներով: Դուք կօգտագործեք bcryptjs՝ շատ օգտակար npm փաթեթ, որը հեշտացնում է կոդավորված գաղտնաբառերի հետ աշխատելը:

Տեղադրեք bcryptjs.

npm i bcryptjs

Փոփոխեք usermodel.js՝ գաղտնաբառը գաղտնագրելու համար, նախքան այն պահելը տվյալների բազայում:

const mongoose = require('mongoose')
const bcrypt = require('bcryptjs');
const {Schema} = mongoose
 
const UserSchema = new Schema ({
...
})
UserSchema.pre('save', async function(next) {
   try {
     // check method of registration
     const user = this;
     if (!user.isModified('password')) next();
     // generate salt
     const salt = await bcrypt.genSalt(10);
     // hash the password
     const hashedPassword = await bcrypt.hash(this.password, salt);
     // replace plain text password with hashed password
     this.password = hashedPassword;
     next();
   } catch (error) {
     return next(error);
   }
 });
...
const User = mongoose.model('User', UserSchema);

Այստեղ դուք օգտագործում եք նախապահպանման կեռը՝ գաղտնաբառը պահպանվելուց առաջ փոփոխելու համար: Գաղափարը պարզ տեքստային գաղտնաբառի փոխարեն գաղտնաբառի հեշ տարբերակը պահելն է: Հեշը երկար բարդ տող է, որը ստեղծվում է պարզ տեքստային տողից:

Օգտագործեք isModified՝ ստուգելու, թե արդյոք գաղտնաբառը փոխվում է, քանի որ անհրաժեշտ է միայն նոր գաղտնաբառեր հաշել: Հաջորդը, ստեղծեք աղ և փոխանցեք այն պարզ տեքստային գաղտնաբառով hash մեթոդին՝ հեշավորված գաղտնաբառ ստեղծելու համար: Վերջապես, փոխարինեք պարզ տեքստային գաղտնաբառը տվյալների բազայում հաշված գաղտնաբառով:

Ստեղծեք db.js և կարգավորեք տվյալների բազան:

const mongoose = require("mongoose");
mongoose.Promise = global.Promise;
const dbUrl = "mongodb://localhost/user";
const connect = async () => {
 mongoose.connect(dbUrl, { useNewUrlParser: true, useUnifiedTopology: true });
 const db = mongoose.connection;
 db.on("error", () => {
   console.log("could not connect");
 });
 db.once("open", () => {
   console.log("> Successfully connected to database");
 });
};
module.exports = { connect };

app.js-ում միացեք տվյալների շտեմարանին:

// connect to db
const db = require('./db');
db.connect();

Քայլ 3. Ստեղծեք անձնագիր

Տեղադրեք Passport և passport-local: Դուք կօգտագործեք այս փաթեթները՝ գրանցման և օգտվողներին մուտք գործելու համար:

npm i passport
npm i passport-local

Ստեղծեք նոր ֆայլ՝ passportConfig.js և ներմուծեք passport-local և userModel.js:

const LocalStraregy = require("passport-local").Strategy;
const User = require("./userModel");

Կազմաձևեք անձնագիրը՝ օգտվողի գրանցումը կարգավորելու համար:

const LocalStrategy = require("passport-local");
const User = require("./userModel");
module.exports = (passport) => {
 passport.use(
   "local-signup",
   new LocalStrategy(
     {
       usernameField: "email",
       passwordField: "password",
     },
     async (email, password, done) => {
       try {
         // check if user exists
         const userExists = await User.findOne({ "email": email });
         if (userExists) {
           return done(null, false)
         }
         // Create a new user with the user data provided
         const user = await User.create({ email, password });
         return done(null, user);
       } catch (error) {
         done(error);
       }
     }
   )
 );
}

Վերոնշյալ կոդում դուք ստուգում եք, թե արդյոք էլփոստն արդեն օգտագործվում է: Եթե էլփոստը գոյություն չունի, գրանցեք օգտվողին: Նկատի ունեցեք, որ դուք նաև կարգավորում եք օգտանունի դաշտը, որպեսզի ընդունի էլ. Լռելյայնորեն, passport-local-ն ակնկալում է օգտվողի անուն, այնպես որ դուք պետք է հայտնեք նրան, որ փոխանցում եք էլ.

Օգտագործեք passport-local՝ նաև օգտատերերի մուտքը կարգավորելու համար:

module.exports = (passport) => {
 passport.use(
   "local-signup",
   new localStrategy(
    ...
   )
 );
passport.use(
   "local-login",
   new LocalStrategy(
     {
       usernameField: "email",
       passwordField: "password",
     },
     async (email, password, done) => {
       try {
         const user = await User.findOne({ email: email });
         if (!user) return done(null, false);
         const isMatch = await user.matchPassword(password);
         if (!isMatch)
           return done(null, false);
         // if passwords match return user
         return done(null, user);
       } catch (error) {
         console.log(error)
         return done(error, false);
       }
     }
   )
 );
};

Այստեղ ստուգեք, թե արդյոք օգտվողը կա տվյալների բազայում, և եթե կա, ստուգեք, արդյոք տրամադրված գաղտնաբառը համընկնում է տվյալների բազայի հետ: Նկատի ունեցեք, որ դուք նաև զանգահարեք matchPassword() մեթոդը օգտագործողի մոդելի վրա, այնպես որ գնացեք userModel.js ֆայլ և ավելացրեք այն:

UserSchema.methods.matchPassword = async function (password) {
 try {
   return await bcrypt.compare(password, this.password);
 } catch (error) {
   throw new Error(error);
 }
};

Այս մեթոդը համեմատում է օգտագործողի և տվյալների բազայի գաղտնաբառը և վերադարձնում է true, եթե դրանք համընկնում են:

Քայլ 4. Ստեղծեք նույնականացման երթուղիներ

Այժմ դուք պետք է ստեղծեք այն վերջնակետերը, որոնց օգտատերերը կուղարկեն տվյալները: Առաջին հերթին գրանցման երթուղին է, որը կընդունի նոր օգտատիրոջ էլ.փոստը և գաղտնաբառը:

app.js-ում օգտագործողին գրանցելու համար օգտագործեք անձնագրային նույնականացման միջին ծրագիրը, որը հենց նոր եք ստեղծել:

app.post(
 "/auth/signup",
 passport.authenticate('local-signup', { session: false }),
 (req, res, next) => {
   // sign up
   res.json({
     user: req.user,
   });
 }
);

Հաջողության դեպքում գրանցման երթուղին պետք է վերադարձնի ստեղծված օգտվողին:

Հաջորդը, ստեղծեք մուտքի երթուղին:

app.post(
 "/auth/login",
 passport.authenticate('local-login', { session: false }),
 (req, res, next) => {
   // login
   res.json({
     user: req.user,
   });
 }
);

Քայլ 5. Ավելացնել պաշտպանված երթուղիներ

Մինչ այժմ դուք օգտագործել եք Անձնագիր՝ ստեղծելու միջին ծրագիր, որը գրանցում է օգտվողին տվյալների բազայում, և մեկ այլ ծրագիր, որը թույլ է տալիս գրանցված օգտվողին մուտք գործել: Այնուհետև դուք կստեղծեք թույլտվության միջնակարգ ծրագիր՝ պաշտպանելու զգայուն երթուղիները՝ օգտագործելով JSON վեբ նշան (JWT): JWT թույլտվությունն իրականացնելու համար անհրաժեշտ է.

  • Ստեղծեք JWT նշան:
  • Փոխանցեք նշանը օգտվողին: Օգտագործողը այն հետ կուղարկի թույլտվության հարցումներում:
  • Ստուգեք օգտատիրոջ կողմից ուղարկված նշանը:

Դուք կօգտագործեք jsonwebtoken փաթեթը JWT-ների հետ աշխատելու համար:

Այն տեղադրելու համար գործարկեք հետևյալ հրամանը.

npm և jsonwebtoken

Հաջորդը, ստեղծեք նշան յուրաքանչյուր օգտվողի համար, որը հաջողությամբ մուտք է գործում:

app.js-ում ներմուծեք jsonwebtoken և փոփոխեք մուտքի երթուղին, ինչպես ստորև:

app.post(
 "/auth/login",
 passport.authenticate('local-login', { session: false }),
 (req, res, next) => {
   // login
   jwt.sign({user: req.user}, 'secretKey', {expiresIn: '1h'}, (err, token) => {
     if(err) {
       return res.json({
         message: "Failed to login",
         token: null,
       });
     }
     res.json({
       token
     });
   })
 }
);

Իրական հավելվածում դուք կօգտագործեք ավելի բարդ գաղտնի բանալի և կպահեք այն կազմաձևման ֆայլում:

Մուտքի երթուղին հաջողության դեպքում վերադարձնում է նշան:

Օգտագործեք passport-jwt պաշտպանված երթուղիներ մուտք գործելու համար:

npm i passport-jwt

passportConfig.js-ում կարգավորեք passport-jwt-ը:

const JwtStrategy = require("passport-jwt").Strategy;
const { ExtractJwt } = require("passport-jwt")
module.exports = (passport) => {
passport.use(
   "local-login",
   new LocalStrategy(
    ...
 );
passport.use(
   new JwtStrategy(
     {
       jwtFromRequest: ExtractJwt.fromHeader("authorization"),
       secretOrKey: "secretKey",
     },
     async (jwtPayload, done) => {
       try {
         // Extract user
         const user = jwtPayload.user;
         done(null, user);
       } catch (error) {
         done(error, false);
       }
     }
   )
 );
};

Ուշադրություն դարձրեք, որ դուք հանում եք JWT-ն թույլտվության վերնագրից՝ հարցման մարմնի փոխարեն: Սա թույլ չի տալիս հաքերներին ընդհատել հարցումը և գրավել նշանը:

Տեսնելու համար, թե ինչպես էpasport-jwt պահպանում երթուղիները, ստեղծեք պաշտպանված երթուղի app.js-ում:

app.get(
 "/user/protected",
 passport.authenticate("jwt", { session: false }),
 (req, res, next) => {
   res.json({user: req.user});
 }
);

Միայն վավեր JWT-ով հարցումը վերադարձնում է օգտատիրոջ տվյալները:

Այժմ դուք պատրաստ եք ձեր օգտատիրոջ նույնականացումը տեղափոխել հաջորդ մակարդակ

Այս ձեռնարկում դուք իմացաք, թե ինչպես կարող եք նույնականացնել օգտատերերին՝ օգտագործելով էլ. փոստ և գաղտնաբառ՝ Passport-ի օգնությամբ: Սկզբում դա կարող է սարսափելի թվալ, բայց գործընթացը համեմատաբար պարզ է: Դուք կարող եք ավելի հեռուն գնալ և օգտվել երրորդ կողմի ինքնության մատակարարներից, որոնք աջակցվում են անձնագրով, ինչպիսիք են Twitter-ը, Facebook-ը և Google-ը: