portaldacalheta.pt
  • Κύριος
  • Επιστήμη Δεδομένων Και Βάσεις Δεδομένων
  • Κατανεμημένες Ομάδες
  • Ευκίνητο Ταλέντο
  • Κερδοφορία & Αποδοτικότητα
Τεχνολογία

Δημιουργία ενός ασφαλούς API REST στο Node.js



Οι διεπαφές προγραμματισμού εφαρμογών (API) είναι παντού. Επιτρέπουν στο λογισμικό να επικοινωνεί με άλλα κομμάτια λογισμικού - εσωτερικά ή εξωτερικά - με συνέπεια, το οποίο αποτελεί βασικό συστατικό της επεκτασιμότητας, για να μην αναφέρουμε την επαναχρησιμοποίηση.

Είναι πολύ συνηθισμένο σήμερα οι διαδικτυακές υπηρεσίες να διαθέτουν API που βλέπουν στο κοινό. Αυτά επιτρέπουν σε άλλους προγραμματιστές να ενσωματώνουν εύκολα λειτουργίες όπως συνδέσεις κοινωνικών μέσων, πληρωμές με πιστωτική κάρτα και παρακολούθηση συμπεριφοράς. ο στην πραγματικότητα Πρότυπο που χρησιμοποιούν για αυτό ονομάζεται REpresentational State Transfer (REST).



Ενώ μια πληθώρα πλατφορμών και γλωσσών προγραμματισμού μπορούν να χρησιμοποιηθούν για την εργασία - π.χ. ASP.NET Core , Laravel (PHP) , ή Μπουκάλι (Python) - σε αυτό το σεμινάριο, θα δημιουργήσουμε ένα βασικό αλλά ασφαλές REST API back end χρησιμοποιώντας την ακόλουθη στοίβα:



  • Node.js, με τον οποίο ο αναγνώστης θα πρέπει να έχει ήδη κάποια εξοικείωση με
  • Express, το οποίο απλοποιεί σε μεγάλο βαθμό τη δημιουργία κοινών εργασιών διακομιστή ιστού στο Node.js και αποτελεί βασικό ναύλο για τη δημιουργία ενός REST API back end
  • Mongoose, το οποίο θα συνδέσει το back-end μας σε μια βάση δεδομένων MongoDB

Οι προγραμματιστές που ακολουθούν αυτό το σεμινάριο θα πρέπει επίσης να είναι άνετοι με το τερματικό (ή τη γραμμή εντολών).



Σημείωση: Δεν θα καλύψουμε εδώ μια βάση κώδικα front-end, αλλά το γεγονός ότι το back-end είναι γραμμένο σε JavaScript καθιστά βολικό να μοιράζεστε κώδικα - μοντέλα αντικειμένων, για παράδειγμα - σε ολόκληρη τη στοίβα.

Ανατομία ενός REST API

Τα REST API χρησιμοποιούνται για πρόσβαση και χειρισμό δεδομένων χρησιμοποιώντας ένα κοινό σύνολο λειτουργιών χωρίς κατάσταση. Αυτές οι λειτουργίες είναι αναπόσπαστες στο πρωτόκολλο HTTP και αντιπροσωπεύουν βασικές λειτουργίες δημιουργίας, ανάγνωσης, ενημέρωσης και διαγραφής (CRUD), αν και όχι με καθαρό τρόπο ένας προς έναν:



  • POST (δημιουργία πόρου ή γενικά παροχή δεδομένων)
  • GET (ανάκτηση ευρετηρίου πόρων ή μεμονωμένου πόρου)
  • PUT (δημιουργία ή αντικατάσταση πόρου)
  • PATCH (ενημέρωση / τροποποίηση ενός πόρου)
  • DELETE (αφαιρέστε έναν πόρο)

Χρησιμοποιώντας αυτές τις λειτουργίες HTTP και ένα όνομα πόρου ως διεύθυνση, μπορούμε να δημιουργήσουμε ένα REST API δημιουργώντας ένα τελικό σημείο για κάθε λειτουργία. Και εφαρμόζοντας το μοτίβο, θα έχουμε ένα σταθερό και εύκολα κατανοητό θεμέλιο που θα μας επιτρέπει να εξελίσσουμε γρήγορα τον κώδικα και να τον διατηρήσουμε μετά. Όπως αναφέρθηκε προηγουμένως, το ίδιο θεμέλιο θα χρησιμοποιηθεί για την ενσωμάτωση λειτουργιών τρίτων, τα περισσότερα από τα οποία χρησιμοποιούν επίσης REST APIs, καθιστώντας την εν λόγω ενσωμάτωση πιο γρήγορη.

Προς το παρόν, ας αρχίσουμε να δημιουργούμε το ασφαλές REST API χρησιμοποιώντας το Node.js!



Σε αυτό το σεμινάριο, θα δημιουργήσουμε ένα αρκετά κοινό (και πολύ πρακτικό) REST API για έναν πόρο που ονομάζεται users.

Ο πόρος μας θα έχει την ακόλουθη βασική δομή:



  • id (ένα UUID που δημιουργήθηκε αυτόματα)
  • firstName
  • lastName
  • email
  • password
  • permissionLevel (τι επιτρέπεται να κάνει αυτός ο χρήστης;)

Και θα δημιουργήσουμε τις ακόλουθες λειτουργίες για αυτόν τον πόρο:

  • POST στο τελικό σημείο /users (δημιουργία νέου χρήστη)
  • GET στο τελικό σημείο /users (λίστα όλων των χρηστών)
  • GET στο τελικό σημείο /users/:userId (πάρτε έναν συγκεκριμένο χρήστη)
  • PATCH στο τελικό σημείο /users/:userId (ενημέρωση των δεδομένων για έναν συγκεκριμένο χρήστη)
  • DELETE στο τελικό σημείο /users/:userId (κατάργηση συγκεκριμένου χρήστη)

Θα χρησιμοποιήσουμε επίσης διακριτικά ιστού JSON (JWTs) για διακριτικά πρόσβασης. Για το σκοπό αυτό, θα δημιουργήσουμε έναν άλλο πόρο που ονομάζεται auth που θα περιμένουν το email και τον κωδικό πρόσβασης ενός χρήστη και, σε αντάλλαγμα, θα δημιουργήσουν το διακριτικό που χρησιμοποιείται για έλεγχο ταυτότητας σε ορισμένες λειτουργίες. (Το υπέροχο άρθρο του Dejan Milosevic για JWT για ασφαλείς εφαρμογές REST στην Java πηγαίνει σε περισσότερες λεπτομέρειες σχετικά με αυτό? οι αρχές είναι οι ίδιες.)



Ρύθμιση εκμάθησης API REST

Πρώτα απ 'όλα, βεβαιωθείτε ότι έχετε εγκαταστήσει την τελευταία έκδοση Node.js. Για αυτό το άρθρο, θα χρησιμοποιώ την έκδοση 14.9.0. Μπορεί επίσης να λειτουργεί σε παλαιότερες εκδόσεις.

Στη συνέχεια, βεβαιωθείτε ότι έχετε MongoDB εγκατεστημένο. Δεν θα εξηγήσουμε τις ιδιαιτερότητες του Mongoose και του MongoDB που χρησιμοποιούνται εδώ, αλλά για να λειτουργήσουν τα βασικά, απλώς ξεκινήστε τον διακομιστή σε διαδραστική λειτουργία (δηλαδή, από τη γραμμή εντολών ως mongo) και όχι ως υπηρεσία. Αυτό συμβαίνει επειδή, σε ένα σημείο σε αυτό το σεμινάριο, θα πρέπει να αλληλεπιδράσουμε με το MongoDB απευθείας και όχι μέσω του κώδικα Node.js.



Σημείωση: Με το MongoDB, δεν χρειάζεται να δημιουργήσετε μια συγκεκριμένη βάση δεδομένων, όπως μπορεί να υπάρχει σε ορισμένα σενάρια RDBMS. Η πρώτη εισαγωγή κλήσης από τον κώδικα Node.js θα ενεργοποιήσει τη δημιουργία της αυτόματα.

Αυτό το σεμινάριο δεν περιέχει όλο τον απαραίτητο κώδικα για ένα έργο που λειτουργεί. Αντ 'αυτού προορίζεται να κλωνοποιήσετε το συνοδευτικό ρεπό και απλώς ακολουθήστε τις καλύτερες στιγμές καθώς διαβάζετε - αλλά μπορείτε επίσης να αντιγράψετε σε συγκεκριμένα αρχεία και αποσπάσματα από το repo, όπως απαιτείται, αν προτιμάτε.

Μεταβείτε στο προκύπτον rest-api-tutorial/ φάκελο στο τερματικό σας. Θα δείτε ότι το έργο μας περιέχει τρεις φακέλους λειτουργικών μονάδων:

  • common (χειρισμός όλων των κοινών υπηρεσιών και πληροφορίες που μοιράζονται μεταξύ των ενοτήτων χρήστη)
  • users (τα πάντα σχετικά με τους χρήστες)
  • auth (χειρισμός της παραγωγής JWT και της ροής σύνδεσης)

Τώρα, εκτελέστε npm install (ή yarn εάν το έχετε.)

Συγχαρητήρια, έχετε πλέον όλες τις εξαρτήσεις και τη ρύθμιση που απαιτούνται για την εκτέλεση του απλού REST API.

Δημιουργία της ενότητας χρήστη

Θα χρησιμοποιούμε Μαγκούστα , μια βιβλιοθήκη μοντελοποίησης δεδομένων αντικειμένων (ODM) για το MongoDB, για τη δημιουργία του μοντέλου χρήστη στο σχήμα χρήστη.

Πρώτον, πρέπει να δημιουργήσουμε το σχήμα Mongoose στο /users/models/users.model.js:

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

Μόλις ορίσουμε το σχήμα, μπορούμε εύκολα να προσαρτήσουμε το σχήμα στο μοντέλο χρήστη.

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

Μετά από αυτό, μπορούμε να χρησιμοποιήσουμε αυτό το μοντέλο για να εφαρμόσουμε όλες τις λειτουργίες CRUD που θέλουμε στα τελικά σημεία Express.

τρέξτε σε ui thread android

Ας ξεκινήσουμε με τη λειτουργία 'δημιουργία χρήστη' καθορίζοντας τη διαδρομή σε users/routes.config.js:

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

Αυτό μεταφέρεται στην εφαρμογή Express στην κύρια index.js αρχείο. Το UsersController το αντικείμενο εισάγεται από τον ελεγκτή μας, όπου έχουμε κατακερματιστεί τον κωδικό πρόσβασης κατάλληλα, όπως ορίζεται στο /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}); }); };

Σε αυτό το σημείο, μπορούμε να δοκιμάσουμε το μοντέλο Mongoose εκτελώντας τον διακομιστή (npm start) και στέλνοντας ένα POST αίτημα προς /users με ορισμένα δεδομένα JSON:

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

Υπάρχουν πολλά εργαλεία που μπορείτε να χρησιμοποιήσετε για αυτό. Η αϋπνία (καλύπτεται παρακάτω) και ο Ταχυδρόμος είναι δημοφιλή εργαλεία GUI και curl είναι μια κοινή επιλογή CLI. Μπορείτε ακόμη και να χρησιμοποιήσετε τη JavaScript, π.χ. από την ενσωματωμένη κονσόλα εργαλείων ανάπτυξης του προγράμματος περιήγησής σας:

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

Σε αυτό το σημείο, το αποτέλεσμα μιας έγκυρης ανάρτησης θα είναι μόνο το αναγνωριστικό από τον δημιουργημένο χρήστη: { 'id': '5b02c5c84817bf28049e58a3' }. Πρέπει επίσης να προσθέσουμε το createUser μέθοδος στο μοντέλο σε users/models/users.model.js:

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

Όλα έτοιμα, τώρα πρέπει να δούμε αν ο χρήστης υπάρχει. Γι 'αυτό, θα εφαρμόσουμε τη λειτουργία 'get user by id' για το ακόλουθο τελικό σημείο: users/:userId.

Αρχικά, δημιουργούμε μια διαδρομή σε /users/routes/config.js:

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

Στη συνέχεια, δημιουργούμε τον ελεγκτή στο /users/controllers/users.controller.js:

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

Και τέλος, προσθέστε το findById μέθοδος στο μοντέλο σε /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; }); };

Η απάντηση θα είναι η εξής:

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

Σημειώστε ότι μπορούμε να δούμε τον κατακερματισμένο κωδικό πρόσβασης. Για αυτό το σεμινάριο, παρουσιάζουμε τον κωδικό πρόσβασης, αλλά η προφανής βέλτιστη πρακτική δεν είναι ποτέ να αποκαλύπτετε τον κωδικό πρόσβασης, ακόμα κι αν έχει κατακερματιστεί. Ένα άλλο πράγμα που μπορούμε να δούμε είναι το permissionLevel, το οποίο θα χρησιμοποιήσουμε για να χειριστούμε τα δικαιώματα χρήστη αργότερα.

Επαναλαμβάνοντας το μοτίβο που περιγράφεται παραπάνω, μπορούμε πλέον να προσθέσουμε τη λειτουργικότητα για ενημέρωση του χρήστη. Θα χρησιμοποιήσουμε το PATCH λειτουργία δεδομένου ότι θα μας επιτρέψει να στείλουμε μόνο τα πεδία που θέλουμε να αλλάξουμε. Επομένως, η διαδρομή θα είναι PATCH στο /users/:userid και θα στέλνουμε τα πεδία που θέλουμε να αλλάξουμε. Θα χρειαστεί επίσης να εφαρμόσουμε κάποια επιπλέον επικύρωση, καθώς οι αλλαγές πρέπει να περιορίζονται στον εν λόγω χρήστη ή έναν διαχειριστή και μόνο ένας διαχειριστής θα πρέπει να μπορεί να αλλάξει το permissionLevel. Θα το παραλείψουμε προς το παρόν και θα το επιστρέψουμε μόλις εφαρμόσουμε τη μονάδα ελέγχου. Προς το παρόν, ο ελεγκτής μας θα μοιάζει με αυτό:

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({}); }); };

Από προεπιλογή, θα στείλουμε έναν κωδικό HTTP 204 χωρίς σώμα απόκρισης για να δείξουμε ότι το αίτημα ήταν επιτυχές.

Και θα πρέπει να προσθέσουμε το patchUser μέθοδος στο μοντέλο:

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

Η λίστα χρηστών θα εφαρμοστεί ως GET στο /users/ από τον ακόλουθο ελεγκτή:

exports.list = (req, res) => { let limit = req.query.limit && req.query.limit { res.status(200).send(result); }) };

Η αντίστοιχη μέθοδος μοντέλου θα είναι:

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

Η προκύπτουσα απόκριση λίστας θα έχει την ακόλουθη δομή:

[ { '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' } ]

Και το τελευταίο μέρος που θα εφαρμοστεί είναι το DELETE στο /users/:userId.

Ο ελεγκτής μας για διαγραφή θα είναι:

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

Όπως και πριν, ο ελεγκτής θα επιστρέψει τον κωδικό HTTP 204 και κανένα σώμα περιεχομένου ως επιβεβαίωση.

Η αντίστοιχη μέθοδος μοντέλου πρέπει να έχει την εξής μορφή:

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

Έχουμε πλέον όλες τις απαραίτητες λειτουργίες για το χειρισμό του πόρου χρήστη και τελειώσαμε με τον ελεγκτή χρήστη Η κύρια ιδέα αυτού του κώδικα είναι να σας δώσει τις βασικές έννοιες της χρήσης του μοτίβου REST. Θα πρέπει να επιστρέψουμε σε αυτόν τον κώδικα για να εφαρμόσουμε ορισμένες επικυρώσεις και δικαιώματα σε αυτόν, αλλά πρώτα, θα πρέπει να αρχίσουμε να δημιουργούμε την ασφάλειά μας. Ας δημιουργήσουμε τη λειτουργική μονάδα.

Δημιουργία της ενότητας Auth

Πριν μπορέσουμε να διασφαλίσουμε το users ενότητα με την εφαρμογή του μέσου άδειας και επικύρωσης, θα πρέπει να είμαστε σε θέση να δημιουργήσουμε ένα έγκυρο διακριτικό για τον τρέχοντα χρήστη. Θα δημιουργήσουμε ένα JWT ως απάντηση στο χρήστη που θα παρέχει έγκυρα email και κωδικό πρόσβασης. Το JWT είναι ένα αξιοσημείωτο διακριτικό ιστού JSON που μπορείτε να χρησιμοποιήσετε για να κάνετε ο χρήστης να υποβάλει με ασφάλεια πολλά αιτήματα χωρίς να επαληθεύει επανειλημμένα. Συνήθως έχει χρόνο λήξης και δημιουργείται ένα νέο διακριτικό κάθε λίγα λεπτά για να διατηρείται η επικοινωνία ασφαλής. Ωστόσο, για αυτό το σεμινάριο, θα ξεχάσουμε την ανανέωση του διακριτικού και θα το κρατήσουμε απλό με ένα διακριτικό ανά σύνδεση.

Αρχικά, θα δημιουργήσουμε ένα τελικό σημείο για το POST αιτήματα για /auth πόρος. Το σώμα του αιτήματος θα περιέχει το email χρήστη και τον κωδικό πρόσβασης:

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

Πριν δεσμεύσουμε τον ελεγκτή, πρέπει να επικυρώσουμε τον χρήστη στο /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']}); } } }); };

Μετά από αυτό, μπορούμε να προχωρήσουμε στον ελεγκτή και να δημιουργήσουμε το 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}); } };

Παρόλο που δεν θα ανανεώσουμε το διακριτικό σε αυτό το σεμινάριο, ο ελεγκτής έχει ρυθμιστεί για να επιτρέψει σε αυτήν τη γενιά να διευκολύνει την εφαρμογή του στην επόμενη ανάπτυξη.

Το μόνο που χρειαζόμαστε τώρα είναι να δημιουργήσουμε τη διαδρομή και να καλέσουμε το κατάλληλο μεσαίο λογισμικό στο /authorization/routes.config.js:

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

Η απόκριση θα περιέχει το δημιουργημένο JWT στο πεδίο accessToken:

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

Αφού δημιουργήσαμε το διακριτικό, μπορούμε να το χρησιμοποιήσουμε μέσα στο Authorization κεφαλίδα χρησιμοποιώντας τη φόρμα Bearer ACCESS_TOKEN.

Δημιουργία αδειών και επικυρώσεων Middleware

Το πρώτο πράγμα που πρέπει να ορίσουμε είναι ποιος μπορεί να χρησιμοποιήσει το users πόρος. Αυτά είναι τα σενάρια που θα πρέπει να χειριστούμε:

  • Δημόσιο για τη δημιουργία χρηστών (διαδικασία εγγραφής). Δεν θα χρησιμοποιήσουμε το JWT για αυτό το σενάριο.
  • Ιδιωτικό για τον συνδεδεμένο χρήστη και για τους διαχειριστές για την ενημέρωση αυτού του χρήστη.
  • Ιδιωτικό για διαχειριστή μόνο για την κατάργηση λογαριασμών χρηστών.

Έχοντας εντοπίσει αυτά τα σενάρια, θα χρειαζόμαστε πρώτα ένα μεσαίο λογισμικό που επικυρώνει πάντα τον χρήστη εάν χρησιμοποιεί ένα έγκυρο JWT. Το μεσαίο λογισμικό σε /common/middlewares/auth.validation.middleware.js μπορεί να είναι τόσο απλό όσο:

πώς να γράψετε έναν κωδικό
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(); } };

Θα χρησιμοποιήσουμε κωδικούς σφάλματος HTTP για τον χειρισμό σφαλμάτων αιτήματος:

  • HTTP 401 για μη έγκυρο αίτημα
  • HTTP 403 για έγκυρο αίτημα με μη έγκυρο διακριτικό ή έγκυρο διακριτικό με μη έγκυρα δικαιώματα

Μπορούμε να χρησιμοποιήσουμε τον τελεστή bitwise AND (bitmasking) για τον έλεγχο των δικαιωμάτων. Εάν ορίσουμε κάθε απαιτούμενη άδεια ως ισχύ 2, μπορούμε να αντιμετωπίσουμε κάθε bit του ακέραιου 32-bit ως ένα μόνο δικαίωμα. Στη συνέχεια, ένας διαχειριστής μπορεί να έχει όλα τα δικαιώματα ορίζοντας την τιμή άδειας σε 2147483647. Αυτός ο χρήστης θα μπορούσε τότε να έχει πρόσβαση σε οποιαδήποτε διαδρομή. Ως άλλο παράδειγμα, ένας χρήστης του οποίου η τιμή δικαιωμάτων ορίστηκε σε 7 θα έχει δικαιώματα για τους ρόλους που επισημαίνονται με bit για τις τιμές 1, 2 και 4 (δύο με ισχύ 0, 1 και 2).

Το μεσαίο λογισμικό για αυτό θα μοιάζει με αυτό:

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

Το μεσαίο λογισμικό είναι γενικό. Εάν το επίπεδο άδειας χρήστη και το απαιτούμενο επίπεδο άδειας συμπίπτουν σε τουλάχιστον ένα bit, το αποτέλεσμα θα είναι μεγαλύτερο από το μηδέν και μπορούμε να αφήσουμε την ενέργεια να προχωρήσει. Διαφορετικά, ο κωδικός HTTP 403 θα επιστραφεί.

Τώρα, πρέπει να προσθέσουμε το ενδιάμεσο λογισμικό ελέγχου ταυτότητας στις διαδρομές της λειτουργικής μονάδας του χρήστη στο /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 ]);

Αυτό ολοκληρώνει τη βασική ανάπτυξη του REST API μας. Το μόνο που μένει να κάνουμε είναι να το δοκιμάσουμε όλα.

Τρέξιμο και δοκιμές με αϋπνία

Αυπνία είναι ένας αξιοπρεπής πελάτης REST με μια καλή δωρεάν έκδοση. Η βέλτιστη πρακτική είναι, φυσικά, να συμπεριλάβετε δοκιμές κώδικα και να εφαρμόσετε σωστή αναφορά σφαλμάτων στο έργο, αλλά οι πελάτες REST τρίτων είναι ιδανικοί για τη δοκιμή και την εφαρμογή λύσεων τρίτων όταν η αναφορά σφαλμάτων και ο εντοπισμός σφαλμάτων δεν είναι διαθέσιμη. Θα το χρησιμοποιήσουμε εδώ για να παίξουμε το ρόλο μιας εφαρμογής και να μάθουμε τι συμβαίνει με το API μας.

Για να δημιουργήσουμε έναν χρήστη, πρέπει απλώς να POST τα απαιτούμενα πεδία στο κατάλληλο τελικό σημείο και αποθηκεύστε το δημιουργημένο αναγνωριστικό για μελλοντική χρήση.

Αίτημα με τα κατάλληλα δεδομένα για τη δημιουργία ενός χρήστη

Το API θα ανταποκριθεί με το αναγνωριστικό χρήστη:

Απάντηση επιβεβαίωσης με το userID

Μπορούμε τώρα να δημιουργήσουμε το JWT χρησιμοποιώντας το /auth/ τελικό σημείο:

Αίτημα με δεδομένα σύνδεσης

Πρέπει να λάβουμε ένα σύμβολο ως απάντηση μας:

Επιβεβαίωση που περιέχει το αντίστοιχο Διακριτικό Ιστού JSON

Πιάστε το accessToken, προθέστε το με Bearer (θυμηθείτε το κενό διάστημα) και προσθέστε το στις κεφαλίδες αιτήματος κάτω από το Authorization:

Η ρύθμιση των κεφαλίδων για μεταφορά περιέχει τον έλεγχο ταυτότητας JWT

Εάν δεν το κάνουμε τώρα που έχουμε εφαρμόσει το ενδιάμεσο λογισμικό αδειών, κάθε αίτημα εκτός από την εγγραφή θα επιστρέφει τον κωδικό HTTP 401. Ωστόσο, με το έγκυρο διακριτικό, λαμβάνουμε την ακόλουθη απάντηση από το /users/:userId:

Απάντηση στην οποία αναφέρονται τα δεδομένα για τον υποδεικνυόμενο χρήστη

Επίσης, όπως αναφέρθηκε προηγουμένως, προβάλλουμε όλα τα πεδία, για εκπαιδευτικούς σκοπούς και για λόγους απλότητας. Ο κωδικός πρόσβασης (κατακερματισμός ή άλλως) δεν πρέπει ποτέ να είναι ορατός στην απόκριση.

Ας προσπαθήσουμε να λάβουμε μια λίστα χρηστών:

Αίτημα για μια λίστα με όλους τους χρήστες

Εκπληξη! Λαμβάνουμε 403 απάντηση.

Η ενέργεια απορρίφθηκε λόγω έλλειψης κατάλληλου επιπέδου άδειας

Ο χρήστης μας δεν έχει τα δικαιώματα πρόσβασης σε αυτό το τελικό σημείο. Θα πρέπει να αλλάξουμε το permissionLevel του χρήστη μας από το 1 έως το 7 (ή ακόμα και 5 θα το έκαναν, δεδομένου ότι τα επίπεδα δωρεάν και πληρωμένων δικαιωμάτων μας αντιπροσωπεύονται ως 1 και 4, αντίστοιχα.) Μπορούμε να το κάνουμε χειροκίνητα στο MongoDB, στη διαδραστική προτροπή του, όπως αυτό (με το αναγνωριστικό άλλαξε στο τοπικό αποτέλεσμα):

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

Στη συνέχεια, πρέπει να δημιουργήσουμε ένα νέο JWT.

Αφού γίνει αυτό, λαμβάνουμε τη σωστή απάντηση:

Απάντηση με όλους τους χρήστες και τα δεδομένα τους

Στη συνέχεια, ας δοκιμάσουμε τη λειτουργικότητα ενημέρωσης στέλνοντας ένα PATCH αίτημα με ορισμένα πεδία στο /users/:userId τελικό σημείο:

Αίτημα που περιέχει μερικά δεδομένα για ενημέρωση

Αναμένουμε μια απάντηση 204 ως επιβεβαίωση μιας επιτυχούς λειτουργίας, αλλά μπορούμε να ζητήσουμε από τον χρήστη να επιβεβαιώσει ξανά.

Απάντηση μετά από επιτυχημένη αλλαγή

Τέλος, πρέπει να διαγράψουμε τον χρήστη. Θα πρέπει να δημιουργήσουμε έναν νέο χρήστη όπως περιγράφεται παραπάνω (μην ξεχάσετε να σημειώσετε το αναγνωριστικό χρήστη) και βεβαιωθείτε ότι διαθέτουμε το κατάλληλο JWT για έναν διαχειριστή. Ο νέος χρήστης θα χρειαστεί τα δικαιώματα που έχει οριστεί σε 2053 (δηλαδή το 2048— ADMIN —επάνω από τα προηγούμενα 5) για να μπορεί επίσης να εκτελέσει τη λειτουργία διαγραφής. Με αυτό που έχει γίνει και δημιουργηθεί ένα νέο JWT, θα πρέπει να ενημερώσουμε το Authorization κεφαλίδα αιτήματος:

Αίτημα ρύθμισης για τη διαγραφή ενός χρήστη

Αποστολή a DELETE αίτημα προς /users/:userId, θα πρέπει να λάβουμε μια απάντηση 204 ως επιβεβαίωση. Μπορούμε, πάλι, να επαληθεύσουμε ζητώντας /users/ για να απαριθμήσετε όλους τους υπάρχοντες χρήστες.

Επόμενα βήματα για το REST API σας

Με τα εργαλεία και τις μεθόδους που καλύπτονται σε αυτό το σεμινάριο, θα πρέπει τώρα να μπορείτε να δημιουργήσετε απλά και ασφαλή REST API στο Node.js. Παραλείφθηκαν πολλές βέλτιστες πρακτικές που δεν είναι απαραίτητες για τη διαδικασία, οπότε μην ξεχάσετε να:

  • Εφαρμογή κατάλληλων επικυρώσεων (π.χ. βεβαιωθείτε ότι το email χρήστη είναι μοναδικό)
  • Εφαρμογή δοκιμών μονάδας και αναφοράς σφαλμάτων
  • Αποτρέψτε τους χρήστες να αλλάξουν το δικό τους επίπεδο άδειας
  • Αποτρέψτε τους διαχειριστές να καταργηθούν
  • Αποτρέψτε την αποκάλυψη ευαίσθητων πληροφοριών (π.χ. κατακερματισμένους κωδικούς πρόσβασης)
  • Μετακινήστε το μυστικό JWT από common/config/env.config.js σε off-repo, χωρίς περιβάλλον μηχανισμός μυστικής διανομής

Μια τελική άσκηση για τον αναγνώστη μπορεί να είναι να μετατρέψει τη βάση κώδικα από τη χρήση των υποσχέσεων JavaScript σε async / περιμένετε τεχνική.

Για όσους από εσάς μπορεί να σας ενδιαφέρουν, υπάρχει και τώρα μια έκδοση TypeScript του διαθέσιμου έργου.

Σχετίζεται με: 5 πράγματα που δεν έχετε κάνει ποτέ με μια προδιαγραφή REST

Τρόπος δημιουργίας API βάσει ρόλου με έλεγχο ταυτότητας Firebase

Διεπαφή Ιστού

Τρόπος δημιουργίας API βάσει ρόλου με έλεγχο ταυτότητας Firebase
Taming WebRTC με PeerJS: Δημιουργία ενός απλού παιχνιδιού Web P2P

Taming WebRTC με PeerJS: Δημιουργία ενός απλού παιχνιδιού Web P2P

Διεπαφή Ιστού

Δημοφιλείς Αναρτήσεις
Πώς να επιλέξετε το καλύτερο πλαίσιο Front-End
Πώς να επιλέξετε το καλύτερο πλαίσιο Front-End
Χρειάζεστε έναν ήρωα: Ο υπεύθυνος έργου
Χρειάζεστε έναν ήρωα: Ο υπεύθυνος έργου
Πώς να βελτιώσετε την απόδοση της εφαρμογής ASP.NET στο Web Farm με προσωρινή αποθήκευση
Πώς να βελτιώσετε την απόδοση της εφαρμογής ASP.NET στο Web Farm με προσωρινή αποθήκευση
Οι δοκιμασμένοι και αληθινοί νόμοι του UX (με Infographic)
Οι δοκιμασμένοι και αληθινοί νόμοι του UX (με Infographic)
Ανώτερος συνεργάτης πελάτη, υγειονομική περίθαλψη και βιοεπιστήμες
Ανώτερος συνεργάτης πελάτη, υγειονομική περίθαλψη και βιοεπιστήμες
 
Η άνοδος των αυτοματοποιημένων συναλλαγών: Μηχανές που εμπορεύονται το S&P 500
Η άνοδος των αυτοματοποιημένων συναλλαγών: Μηχανές που εμπορεύονται το S&P 500
10 πιο κοινές ευπάθειες ασφαλείας στον Ιστό
10 πιο κοινές ευπάθειες ασφαλείας στον Ιστό
Σκέψεις για τη συγκέντρωση του ιδιωτικού σας αμοιβαίου κεφαλαίου
Σκέψεις για τη συγκέντρωση του ιδιωτικού σας αμοιβαίου κεφαλαίου
Διευθυντής έργου και διαχείρισης προϊόντων
Διευθυντής έργου και διαχείρισης προϊόντων
Η σημασία της διατήρησης πελατών - μια εμπειρική μελέτη
Η σημασία της διατήρησης πελατών - μια εμπειρική μελέτη
Δημοφιλείς Αναρτήσεις
  • τι μπορείτε να κάνετε με το ρουμπίνι σε ράγες
  • κόμβος js έναντι απόδοσης python
  • μετεγκατάσταση διακομιστή sql στο oracle
  • μέτρα ελαστικότητας τιμής της ζήτησης__________
  • adobe experience design vs σκίτσο
Κατηγορίες
  • Επιστήμη Δεδομένων Και Βάσεις Δεδομένων
  • Κατανεμημένες Ομάδες
  • Ευκίνητο Ταλέντο
  • Κερδοφορία & Αποδοτικότητα
  • © 2022 | Ολα Τα Δικαιώματα Διατηρούνται

    portaldacalheta.pt