Crearea unui API REST securizat în Node.js

Publicat: 2022-03-11

Interfețele de programare a aplicațiilor (API) sunt peste tot. Acestea permit software-ului să comunice cu alte componente software – interne sau externe – în mod constant, ceea ce este un ingredient cheie în scalabilitate, ca să nu mai vorbim de reutilizare.

În zilele noastre, este destul de comun ca serviciile online să aibă API-uri destinate publicului. Acestea permit altor dezvoltatori să integreze cu ușurință funcții precum autentificarea la rețelele sociale, plățile cu cardul de credit și urmărirea comportamentului. Standardul de facto pe care îl folosesc pentru aceasta se numește Transferul de stat REprezentațional (REST).

În timp ce o multitudine de platforme și limbaje de programare pot fi utilizate pentru sarcină - de exemplu, ASP.NET Core, Laravel (PHP) sau Bottle (Python) - în acest tutorial, vom construi un back-end API REST de bază, dar sigur, folosind următorul teanc:

  • Node.js, cu care cititorul ar trebui să fie deja familiarizat
  • Express, care simplifică foarte mult construirea sarcinilor comune ale serverului web sub Node.js și este tariful standard în construirea unui back-end API REST
  • Mongoose, care va conecta back-end-ul nostru la o bază de date MongoDB

Dezvoltatorii care urmează acest tutorial ar trebui, de asemenea, să fie confortabili cu terminalul (sau promptul de comandă).

Notă: nu vom acoperi aici o bază de cod front-end, dar faptul că back-end-ul nostru este scris în JavaScript face convenabil să partajăm codul – modele de obiecte, de exemplu – în întreaga stivă.

Anatomia unui API REST

API-urile REST sunt folosite pentru a accesa și manipula date folosind un set comun de operațiuni fără stat. Aceste operațiuni sunt parte integrantă a protocolului HTTP și reprezintă funcționalitatea esențială de creare, citire, actualizare și ștergere (CRUD), deși nu într-un mod curat unu-la-unu:

  • POST (creați o resursă sau furnizați în general date)
  • GET (preluare un index de resurse sau o resursă individuală)
  • PUT (creați sau înlocuiți o resursă)
  • PATCH (actualizare/modificarea unei resurse)
  • DELETE (elimină o resursă)

Folosind aceste operațiuni HTTP și un nume de resursă ca adresă, putem construi un API REST prin crearea unui punct final pentru fiecare operațiune. Și prin implementarea modelului, vom avea o bază stabilă și ușor de înțeles care ne va permite să evoluăm rapid codul și să-l menținem ulterior. După cum am menționat anterior, aceeași fundație va fi folosită pentru a integra funcții terțe, dintre care majoritatea folosesc, de asemenea, API-uri REST, făcând o astfel de integrare mai rapidă.

Deocamdată, să începem să creăm API-ul nostru REST securizat folosind Node.js!

În acest tutorial, vom crea un API REST destul de comun (și foarte practic) pentru o resursă numită users .

Resursa noastră va avea următoarea structură de bază:

  • id (un UUID generat automat)
  • firstName
  • lastName
  • email
  • password
  • permissionLevel (ce poate face acest utilizator?)

Și vom crea următoarele operațiuni pentru resursa respectivă:

  • POST pe punctul final /users (creați un utilizator nou)
  • GET pe punctul final /users (lista toți utilizatorii)
  • GET pe punctul final /users/:userId (obțineți un anumit utilizator)
  • PATCH pe punctul final /users/:userId (actualizați datele pentru un anumit utilizator)
  • DELETE pe punctul final /users/:userId (eliminați un anumit utilizator)

Vom folosi, de asemenea, jetoane web JSON (JWT) pentru jetoane de acces. În acest scop, vom crea o altă resursă numită auth care va aștepta e-mailul și parola unui utilizator și, în schimb, va genera token-ul folosit pentru autentificare la anumite operațiuni. (Marele articol al lui Dejan Milosevic despre JWT pentru aplicații REST sigure în Java intră în mai multe detalii despre aceasta; principiile sunt aceleași.)

Tutorial Configurare REST API

În primul rând, asigurați-vă că aveți instalată cea mai recentă versiune Node.js. Pentru acest articol, voi folosi versiunea 14.9.0; poate funcționa și pe versiuni mai vechi.

Apoi, asigurați-vă că aveți instalat MongoDB. Nu vom explica specificul Mongoose și MongoDB care sunt folosite aici, dar pentru a începe să ruleze elementele de bază, pur și simplu porniți serverul în modul interactiv (adică din linia de comandă ca mongo ) și nu ca serviciu. Asta pentru că, la un moment dat în acest tutorial, va trebui să interacționăm cu MongoDB direct, mai degrabă decât prin codul nostru Node.js.

Notă: Cu MongoDB, nu este nevoie să creați o anumită bază de date, așa cum ar putea fi în unele scenarii RDBMS. Primul apel de inserare din codul nostru Node.js va declanșa automat crearea acestuia.

Acest tutorial nu conține tot codul necesar pentru un proiect de lucru. În schimb, se intenționează să cloneze depozitul însoțitor și să urmeze pur și simplu elementele evidențiate pe măsură ce citiți, dar puteți, de asemenea, să copiați anumite fișiere și fragmente din depozit după cum este necesar, dacă preferați.

Navigați la folderul rezultat rest-api-tutorial/ din terminalul dvs. Veți vedea că proiectul nostru conține trei foldere de module:

  • common (se gestionează toate serviciile partajate și informațiile partajate între modulele utilizator)
  • users (tot ce se referă la utilizatori)
  • auth (se gestionează generarea JWT și fluxul de conectare)

Acum, rulați npm install (sau yarn dacă îl aveți.)

Felicitări, acum aveți toate dependențele și configurațiile necesare pentru a rula back-end-ul nostru simplu REST API.

Crearea modulului utilizator

Vom folosi Mongoose, o bibliotecă de modelare a datelor obiect (ODM) pentru MongoDB, pentru a crea modelul utilizatorului în schema utilizatorului.

În primul rând, trebuie să creăm schema Mongoose în /users/models/users.model.js :

 const userSchema = new Schema({ firstName: String, lastName: String, email: String, password: String, permissionLevel: Number });

Odată ce definim schema, putem atașa cu ușurință schema la modelul utilizatorului.

 const userModel = mongoose.model('Users', userSchema);

După aceea, putem folosi acest model pentru a implementa toate operațiunile CRUD pe care le dorim în punctele noastre finale Express.

Să începem cu operația de „creare utilizator” prin definirea rutei în users/routes.config.js :

 app.post('/users', [ UsersController.insert ]);

Acesta este introdus în aplicația noastră Express în fișierul principal index.js . Obiectul UsersController este importat de la controlerul nostru, unde se hash parola în mod corespunzător, definită în /users/controllers/users.controller.js :

 exports.insert = (req, res) => { let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512',salt) .update(req.body.password) .digest("base64"); req.body.password = salt + "$" + hash; req.body.permissionLevel = 1; UserModel.createUser(req.body) .then((result) => { res.status(201).send({id: result._id}); }); };

În acest moment, putem testa modelul nostru Mongoose rulând serverul ( npm start ) și trimițând o solicitare POST către /users cu câteva date JSON:

 { "firstName" : "Marcos", "lastName" : "Silva", "email" : "[email protected]", "password" : "s3cr3tp4sswo4rd" }

Există mai multe instrumente pe care le puteți folosi pentru aceasta. Insomnia (acoperite mai jos) și Postman sunt instrumente GUI populare, iar curl este o alegere CLI obișnuită. Puteți chiar să utilizați JavaScript, de exemplu, din consola de instrumente de dezvoltare încorporată a browserului dvs.:

 fetch('http://localhost:3600/users', { method: 'POST', headers: { "Content-type": "application/json" }, body: JSON.stringify({ "firstName": "Marcos", "lastName": "Silva", "email": "[email protected]", "password": "s3cr3tp4sswo4rd" }) }) .then(function(response) { return response.json(); }) .then(function(data) { console.log('Request succeeded with JSON response', data); }) .catch(function(error) { console.log('Request failed', error); });

În acest moment, rezultatul unei postări valide va fi doar id-ul utilizatorului creat: { "id": "5b02c5c84817bf28049e58a3" } . Trebuie să adăugăm și metoda createUser la modelul din users/models/users.model.js :

 exports.createUser = (userData) => { const user = new User(userData); return user.save(); };

Gata, acum trebuie să vedem dacă utilizatorul există. Pentru aceasta, vom implementa caracteristica „obține utilizator prin id” pentru următorul punct final: users/:userId .

Mai întâi, creăm o rută în /users/routes/config.js :

 app.get('/users/:userId', [ UsersController.getById ]);

Apoi, creăm controlerul în /users/controllers/users.controller.js :

 exports.getById = (req, res) => { UserModel.findById(req.params.userId).then((result) => { res.status(200).send(result); }); };

Și, în sfârșit, adăugați metoda findById la modelul din /users/models/users.model.js :

 exports.findById = (id) => { return User.findById(id).then((result) => { result = result.toJSON(); delete result._id; delete result.__v; return result; }); };

Răspunsul va fi astfel:

 { "firstName": "Marcos", "lastName": "Silva", "email": "[email protected]", "password": "Y+XZEaR7J8xAQCc37nf1rw==$p8b5ykUx6xpC6k8MryDaRmXDxncLumU9mEVabyLdpotO66Qjh0igVOVerdqAh+CUQ4n/E0z48mp8SDTpX2ivuQ==", "permissionLevel": 1, "id": "5b02c5c84817bf28049e58a3" }

Rețineți că putem vedea parola codificată. Pentru acest tutorial, arătăm parola, dar cea mai bună practică evidentă este să nu dezvăluiți niciodată parola, chiar dacă aceasta a fost hashing. Un alt lucru pe care îl putem vedea este permissionLevel , pe care îl vom folosi pentru a gestiona permisiunile utilizatorului mai târziu.

Repetând modelul prezentat mai sus, acum putem adăuga funcționalitatea pentru a actualiza utilizatorul. Vom folosi operația PATCH deoarece ne va permite să trimitem doar câmpurile pe care dorim să le schimbăm. Prin urmare, ruta va fi PATCH către /users/:userid și vom trimite orice câmpuri pe care dorim să le schimbăm. De asemenea, va trebui să implementăm o validare suplimentară, deoarece modificările ar trebui să fie limitate la utilizatorul în cauză sau la un administrator și doar un administrator ar trebui să poată schimba permissionLevel . Vom sări peste asta pentru moment și vom reveni la el odată ce implementăm modulul de autentificare. Deocamdată, controlerul nostru va arăta astfel:

 exports.patchById = (req, res) => { if (req.body.password){ let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(req.body.password).digest("base64"); req.body.password = salt + "$" + hash; } UserModel.patchUser(req.params.userId, req.body).then((result) => { res.status(204).send({}); }); };

În mod implicit, vom trimite un cod HTTP 204 fără corp de răspuns pentru a indica faptul că solicitarea a avut succes.

Și va trebui să adăugăm metoda patchUser la model:

 exports.patchUser = (id, userData) => { return User.findOneAndUpdate({ _id: id }, userData); };

Lista de utilizatori va fi implementată ca GET la /users/ de către următorul controlor:

 exports.list = (req, res) => { let limit = req.query.limit && req.query.limit <= 100 ? parseInt(req.query.limit) : 10; let page = 0; if (req.query) { if (req.query.page) { req.query.page = parseInt(req.query.page); page = Number.isInteger(req.query.page) ? req.query.page : 0; } } UserModel.list(limit, page).then((result) => { res.status(200).send(result); }) };

Metoda modelului corespunzătoare va fi:

 exports.list = (perPage, page) => { return new Promise((resolve, reject) => { User.find() .limit(perPage) .skip(perPage * page) .exec(function (err, users) { if (err) { reject(err); } else { resolve(users); } }) }); };

Răspunsul listei rezultat va avea următoarea structură:

 [ { "firstName": "Marco", "lastName": "Silva", "email": "[email protected]", "password": "z4tS/DtiH+0Gb4J6QN1K3w==$al6sGxKBKqxRQkDmhnhQpEB6+DQgDRH2qr47BZcqLm4/fphZ7+a9U+HhxsNaSnGB2l05Oem/BLIOkbtOuw1tXA==", "permissionLevel": 1, "id": "5b02c5c84817bf28049e58a3" }, { "firstName": "Paulo", "lastName": "Silva", "email": "[email protected]", "password": "wTsqO1kHuVisfDIcgl5YmQ==$cw7RntNrNBNw3MO2qLbx959xDvvrDu4xjpYfYgYMxRVDcxUUEgulTlNSBJjiDtJ1C85YimkMlYruU59rx2zbCw==", "permissionLevel": 1, "id": "5b02d038b653603d1ca69729" } ]

Și ultima parte care trebuie implementată este DELETE la /users/:userId .

Controlerul nostru pentru ștergere va fi:

 exports.removeById = (req, res) => { UserModel.removeById(req.params.userId) .then((result)=>{ res.status(204).send({}); }); };

La fel ca și înainte, controlerul va returna codul HTTP 204 și niciun corp de conținut ca confirmare.

Metoda de model corespunzătoare ar trebui să arate astfel:

 exports.removeById = (userId) => { return new Promise((resolve, reject) => { User.deleteMany({_id: userId}, (err) => { if (err) { reject(err); } else { resolve(err); } }); }); };

Acum avem toate operațiunile necesare pentru manipularea resursei utilizatorului și am terminat cu controlerul utilizatorului. Ideea principală a acestui cod este să vă ofere conceptele de bază ale utilizării modelului REST. Va trebui să revenim la acest cod pentru a implementa unele validări și permisiuni pentru el, dar mai întâi va trebui să începem să ne construim securitatea. Să creăm modulul de autentificare.

Crearea modulului de autentificare

Înainte de a putea securiza modulul users prin implementarea middleware-ului de permisiune și validare, va trebui să putem genera un token valid pentru utilizatorul curent. Vom genera un JWT ca răspuns la furnizarea utilizatorului de o e-mail și o parolă valide. JWT este un token web JSON remarcabil pe care îl puteți folosi pentru ca utilizatorul să facă mai multe solicitări în siguranță, fără a valida în mod repetat. De obicei, are un timp de expirare și un nou token este recreat la fiecare câteva minute pentru a menține comunicarea în siguranță. Pentru acest tutorial, totuși, vom renunța la reîmprospătarea token-ului și îl vom păstra simplu cu un singur token per autentificare.

Mai întâi, vom crea un punct final pentru solicitările POST către resursa /auth . Corpul solicitării va conține e-mailul utilizatorului și parola:

 { "email" : "[email protected]", "password" : "s3cr3tp4sswo4rd2" }

Înainte de a angaja controlerul, ar trebui să validăm utilizatorul în /authorization/middlewares/verify.user.middleware.js :

 exports.isPasswordAndUserMatch = (req, res, next) => { UserModel.findByEmail(req.body.email) .then((user)=>{ if(!user[0]){ res.status(404).send({}); }else{ let passwordFields = user[0].password.split('$'); let salt = passwordFields[0]; let hash = crypto.createHmac('sha512', salt).update(req.body.password).digest("base64"); if (hash === passwordFields[1]) { req.body = { userId: user[0]._id, email: user[0].email, permissionLevel: user[0].permissionLevel, provider: 'email', name: user[0].firstName + ' ' + user[0].lastName, }; return next(); } else { return res.status(400).send({errors: ['Invalid email or password']}); } } }); };

După ce am făcut asta, putem trece la controler și putem genera JWT:

 exports.login = (req, res) => { try { let refreshId = req.body.userId + jwtSecret; let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(refreshId).digest("base64"); req.body.refreshKey = salt; let token = jwt.sign(req.body, jwtSecret); let b = Buffer.from(hash); let refresh_token = b.toString('base64'); res.status(201).send({accessToken: token, refreshToken: refresh_token}); } catch (err) { res.status(500).send({errors: err}); } };

Chiar dacă nu vom reîmprospăta jetonul în acest tutorial, controlerul a fost configurat pentru a permite o astfel de generare pentru a facilita implementarea acestuia în dezvoltarea ulterioară.

Tot ce avem nevoie acum este să creăm ruta și să invocăm middleware-ul corespunzător în /authorization/routes.config.js :

 app.post('/auth', [ VerifyUserMiddleware.hasAuthValidFields, VerifyUserMiddleware.isPasswordAndUserMatch, AuthorizationController.login ]);

Răspunsul va conține JWT generat în câmpul accessToken:

 { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1YjAyYzVjODQ4MTdiZjI4MDQ5ZTU4YTMiLCJlbWFpbCI6Im1hcmNvcy5oZW5yaXF1ZUB0b3B0YWwuY29tIiwicGVybWlzc2lvbkxldmVsIjoxLCJwcm92aWRlciI6ImVtYWlsIiwibmFtZSI6Ik1hcmNvIFNpbHZhIiwicmVmcmVzaF9rZXkiOiJiclhZUHFsbUlBcE1PakZIRG1FeENRPT0iLCJpYXQiOjE1MjY5MjMzMDl9.mmNg-i44VQlUEWP3YIAYXVO-74803v1mu-y9QPUQ5VY", "refreshToken": "U3BDQXBWS3kyaHNDaGJNanlJTlFkSXhLMmFHMzA2NzRsUy9Sd2J0YVNDTmUva0pIQ0NwbTJqOU5YZHgxeE12NXVlOUhnMzBWMGNyWmdOTUhSaTdyOGc9PQ==" }

După ce am creat jetonul, îl putem folosi în antetul Authorization folosind formularul Bearer ACCESS_TOKEN .

Crearea de Permisiuni și Validări Middleware

Primul lucru pe care ar trebui să-l definim este cine poate folosi resursa users . Acestea sunt scenariile pe care va trebui să le gestionăm:

  • Public pentru crearea de utilizatori (proces de înregistrare). Nu vom folosi JWT pentru acest scenariu.
  • Privat pentru utilizatorul conectat și pentru administratorii să actualizeze acel utilizator.
  • Privat pentru administrator numai pentru eliminarea conturilor de utilizator.

După identificarea acestor scenarii, vom solicita mai întâi un middleware care validează întotdeauna utilizatorul dacă folosește un JWT valid. Middleware-ul din /common/middlewares/auth.validation.middleware.js poate fi la fel de simplu ca:

 exports.validJWTNeeded = (req, res, next) => { if (req.headers['authorization']) { try { let authorization = req.headers['authorization'].split(' '); if (authorization[0] !== 'Bearer') { return res.status(401).send(); } else { req.jwt = jwt.verify(authorization[1], secret); return next(); } } catch (err) { return res.status(403).send(); } } else { return res.status(401).send(); } };

Vom folosi coduri de eroare HTTP pentru gestionarea erorilor de solicitare:

  • HTTP 401 pentru o solicitare nevalidă
  • HTTP 403 pentru o solicitare validă cu un simbol nevalid sau un simbol valid cu permisiuni nevalide

Putem folosi operatorul AND pe biți (bitmasking) pentru a controla permisiunile. Dacă setăm fiecare permisiunea necesară ca o putere de 2, putem trata fiecare bit al întregului pe 32 de biți ca o singură permisiune. Un administrator poate avea apoi toate permisiunile setând valoarea permisiunii la 2147483647. Acest utilizator ar putea avea apoi acces la orice rută. Ca un alt exemplu, un utilizator a cărui valoare a permisiunii a fost setată la 7 ar avea permisiuni pentru rolurile marcate cu biți pentru valorile 1, 2 și 4 (doi la puterea 0, 1 și 2).

Middleware-ul pentru asta ar arăta astfel:

 exports.minimumPermissionLevelRequired = (required_permission_level) => { return (req, res, next) => { let user_permission_level = parseInt(req.jwt.permission_level); let user_id = req.jwt.user_id; if (user_permission_level & required_permission_level) { return next(); } else { return res.status(403).send(); } }; };

Middleware-ul este generic. Dacă nivelul permisiunii utilizatorului și nivelul permisiunii necesare coincid în cel puțin un bit, rezultatul va fi mai mare decât zero și putem lăsa acțiunea să continue; în caz contrar, va fi returnat codul HTTP 403.

Acum, trebuie să adăugăm middleware-ul de autentificare la rutele modulului utilizatorului în /users/routes.config.js :

 app.post('/users', [ UsersController.insert ]); app.get('/users', [ ValidationMiddleware.validJWTNeeded, PermissionMiddleware.minimumPermissionLevelRequired(PAID), UsersController.list ]); app.get('/users/:userId', [ ValidationMiddleware.validJWTNeeded, PermissionMiddleware.minimumPermissionLevelRequired(FREE), PermissionMiddleware.onlySameUserOrAdminCanDoThisAction, UsersController.getById ]); app.patch('/users/:userId', [ ValidationMiddleware.validJWTNeeded, PermissionMiddleware.minimumPermissionLevelRequired(FREE), PermissionMiddleware.onlySameUserOrAdminCanDoThisAction, UsersController.patchById ]); app.delete('/users/:userId', [ ValidationMiddleware.validJWTNeeded, PermissionMiddleware.minimumPermissionLevelRequired(ADMIN), UsersController.removeById ]);

Aceasta încheie dezvoltarea de bază a API-ului nostru REST. Tot ce rămâne de făcut este să testăm totul.

Alergarea și testarea cu insomnie

Insomnia este un client REST decent cu o versiune gratuită bună. Cea mai bună practică este, desigur, să includeți teste de cod și să implementați raportarea corectă a erorilor în proiect, dar clienții REST terți sunt grozavi pentru testarea și implementarea soluțiilor terțe atunci când raportarea erorilor și depanarea serviciului nu sunt disponibile. O vom folosi aici pentru a juca rolul unei aplicații și pentru a obține o perspectivă asupra a ceea ce se întâmplă cu API-ul nostru.

Pentru a crea un utilizator, trebuie doar să POST câmpurile necesare la punctul final corespunzător și să stocăm ID-ul generat pentru utilizare ulterioară.

Solicitare cu datele corespunzătoare pentru crearea unui utilizator

API-ul va răspunde cu ID-ul de utilizator:

Răspuns de confirmare cu userID

Acum putem genera JWT folosind punctul final /auth/ :

Solicitare cu datele de conectare

Ar trebui să primim un simbol ca răspuns:

Confirmare care conține tokenul web JSON corespunzător

Luați accessToken -ul, prefixați-l cu Bearer (amintiți-vă spațiul) și adăugați-l la antetele cererii sub Authorization :

Configurarea antetelor pentru transfer conține JWT de autentificare

Dacă nu facem acest lucru acum, după ce am implementat middleware-ul de permisiuni, fiecare cerere, în afară de înregistrare, va returna codul HTTP 401. Cu token-ul valid, totuși, primim următorul răspuns de la /users/:userId :

Răspuns care listează datele pentru utilizatorul indicat

De asemenea, așa cum am menționat anterior, afișăm toate domeniile, în scop educațional și de dragul simplității. Parola (hashed sau altfel) nu ar trebui să fie niciodată vizibilă în răspuns.

Să încercăm să obținem o listă de utilizatori:

Solicitați o listă cu toți utilizatorii

Surprinde! Primim un răspuns 403.

Acțiune refuzată din cauza lipsei unui nivel adecvat de permisiune

Utilizatorul nostru nu are permisiunile pentru a accesa acest punct final. Va trebui să schimbăm permissionLevel al utilizatorului nostru de la 1 la 7 (sau chiar 5 ar face, deoarece nivelurile noastre de permisiuni gratuite și plătite sunt reprezentate ca 1 și, respectiv, 4.) Putem face acest lucru manual în MongoDB, la promptul său interactiv. , astfel (cu ID-ul schimbat în rezultatul local):

 db.users.update({"_id" : ObjectId("5b02c5c84817bf28049e58a3")},{$set:{"permissionLevel":5}})

Apoi, trebuie să generăm un nou JWT.

După ce s-a terminat, obținem răspunsul potrivit:

Răspuns cu toți utilizatorii și datele acestora

În continuare, să testăm funcționalitatea de actualizare trimițând o solicitare PATCH cu câteva câmpuri către punctul nostru final /users/:userId :

Solicitare care conține date parțiale de actualizat

Ne așteptăm la un răspuns 204 ca confirmare a unei operațiuni de succes, dar putem solicita utilizatorului încă o dată să verifice.

Răspuns după schimbarea cu succes

În cele din urmă, trebuie să ștergem utilizatorul. Va trebui să creăm un utilizator nou, așa cum este descris mai sus (nu uitați să notați ID-ul utilizatorului) și să ne asigurăm că avem JWT adecvat pentru un utilizator admin. Noul utilizator va avea nevoie de permisiunile setate la 2053 (adică 2048— ADMIN —plus 5 anterioare) pentru a putea efectua și operația de ștergere. După ce s-a terminat și un nou JWT generat, va trebui să ne actualizăm antetul cererii Authorization :

Solicitați configurarea pentru ștergerea unui utilizator

Trimițând o solicitare DELETE către /users/:userId , ar trebui să primim un răspuns 204 ca confirmare. Putem, din nou, să verificăm solicitând /users/ să listăm toți utilizatorii existenți.

Următorii pași pentru API-ul dvs. REST

Cu instrumentele și metodele prezentate în acest tutorial, acum ar trebui să puteți crea API-uri REST simple și sigure pe Node.js. O mulțime de bune practici care nu sunt esențiale pentru proces au fost omise, așa că nu uitați să:

  • Implementați validări adecvate (de exemplu, asigurați-vă că e-mailul utilizatorului este unic)
  • Implementați testarea unitară și raportarea erorilor
  • Împiedicați utilizatorii să-și schimbe propriul nivel de permisiune
  • Împiedicați administratorii să se elimine
  • Preveniți dezvăluirea informațiilor sensibile (de exemplu, parole cu hashing)
  • Mutați secretul JWT de la common/config/env.config.js într-un mecanism de distribuție secretă în afara repo, care nu este bazat pe mediu

Un ultim exercițiu pentru cititor poate fi convertirea bazei de cod de la utilizarea promisiunilor JavaScript la tehnica asincronă/așteptă.

Pentru cei dintre voi care ar putea fi interesați, există acum și o versiune TypeScript a proiectului disponibilă.

Înrudit: 5 lucruri pe care nu le-ați făcut niciodată cu o specificație REST