Με την αυξανόμενη δημοτικότητα των εφαρμογών μιας σελίδας, των εφαρμογών για κινητά και των υπηρεσιών RESTful API, ο τρόπος προγραμματιστές ιστού ο κώδικας back-end εγγραφής έχει αλλάξει σημαντικά. Με τεχνολογίες όπως το AngularJS και το BackboneJS, δεν ξοδεύουμε πλέον πολύ χρόνο για τη δημιουργία σήμανσης, αντί για τη δημιουργία API που καταναλώνουν οι εφαρμογές μας. Το back-end μας αφορά περισσότερο την επιχειρηματική λογική και τα δεδομένα, ενώ η λογική παρουσίασης μεταφέρεται αποκλειστικά στις εφαρμογές διεπαφής ή σε κινητές συσκευές. Αυτές οι αλλαγές οδήγησαν σε νέους τρόπους εφαρμογής του ελέγχου ταυτότητας σε σύγχρονες εφαρμογές.
Ο έλεγχος ταυτότητας είναι ένα από τα πιο σημαντικά μέρη οποιασδήποτε εφαρμογής ιστού. Για δεκαετίες, τα cookie και ο έλεγχος ταυτότητας βάσει διακομιστή ήταν η ευκολότερη λύση. Ωστόσο, ο χειρισμός του ελέγχου ταυτότητας σε σύγχρονες εφαρμογές για κινητά και μεμονωμένες σελίδες μπορεί να είναι δύσκολος και απαιτεί καλύτερη προσέγγιση. Οι πιο γνωστές λύσεις σε προβλήματα ελέγχου ταυτότητας για API είναι οι OAuth 2.0 και το Διακριτικό Web JSON (JWT).
Πριν μπείτε σε αυτό το σεμινάριο JSON Web Token, τι ακριβώς είναι το JWT;
Ένα JSON Web Token χρησιμοποιείται για την αποστολή πληροφοριών που μπορούν να επαληθευτούν και να εμπιστευθούν μέσω ψηφιακής υπογραφής. Περιλαμβάνει ένα συμπαγές και ασφαλές URL αντικείμενο JSON, το οποίο υπογράφεται κρυπτογραφικά για να επαληθεύσει την αυθεντικότητά του και το οποίο μπορεί επίσης να κρυπτογραφηθεί εάν το ωφέλιμο φορτίο περιέχει ευαίσθητες πληροφορίες.
Λόγω της συμπαγούς δομής του, το JWT χρησιμοποιείται συνήθως σε HTTP Authorization
κεφαλίδες ή παράμετροι ερωτήματος URL.
Ένα JWT αντιπροσωπεύεται ως μια ακολουθία του base64url κωδικοποιημένες τιμές που διαχωρίζονται με χαρακτήρες τελείας.
Ακολουθεί ένα παράδειγμα διακριτικού JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0. yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw
Η κεφαλίδα περιέχει τα μεταδεδομένα για το διακριτικό και περιέχει τουλάχιστον τον τύπο της υπογραφής και τον αλγόριθμο κρυπτογράφησης. (Μπορείτε να χρησιμοποιήσετε ένα Διαμορφωτής JSON εργαλείο για να προωθήσει το αντικείμενο JSON.)
Παράδειγμα κεφαλίδας
{ 'alg': 'HS256', 'typ': 'JWT' }
Αυτή η κεφαλίδα παραδείγματος JWT δηλώνει ότι το κωδικοποιημένο αντικείμενο είναι ένα Διακριτικό Ιστού JSON και ότι υπογράφεται χρησιμοποιώντας τον αλγόριθμο HMAC SHA-256.
Μόλις κωδικοποιηθεί base64, έχουμε το πρώτο μέρος του JWT μας.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Στο πλαίσιο του JWT, μια αξίωση μπορεί να οριστεί ως δήλωση σχετικά με μια οντότητα (συνήθως ο χρήστης), καθώς και πρόσθετα μεταδεδομένα σχετικά με το ίδιο το διακριτικό. Η αξίωση περιέχει τις πληροφορίες που θέλουμε να μεταδώσουμε και ότι ο διακομιστής μπορεί να χρησιμοποιήσει για να χειριστεί σωστά τον έλεγχο ταυτότητας JSON Web Token. Υπάρχουν πολλές αξιώσεις που μπορούμε να παρέχουμε. Αυτές περιλαμβάνουν καταχωρημένα ονόματα αξιώσεων, δημόσια ονόματα αξιώσεων και ονόματα ιδιωτικών αξιώσεων.
Εγγεγραμμένες αξιώσεις JWT
Αυτές είναι οι αξιώσεις που καταχωρούνται στο IANA JSON Web Token Claims μητρώου . Αυτές οι αξιώσεις JWT δεν προορίζονται να είναι υποχρεωτικές, αλλά να παρέχουν ένα σημείο εκκίνησης για ένα σύνολο χρήσιμων, διαλειτουργικών αξιώσεων.
Αυτά περιλαμβάνουν:
Δημόσιες αξιώσεις
Οι δημόσιες αξιώσεις πρέπει να έχουν ανθεκτικά σε σύγκρουση ονόματα. Κάνοντας το όνομα URI ή URN, αποφεύγονται συγκρούσεις ονομάτων για JWT όπου ο αποστολέας και ο παραλήπτης δεν αποτελούν μέρος ενός κλειστού δικτύου.
Ένα παράδειγμα δημόσιου ονόματος αξίωσης θα μπορούσε να είναι: https://www.toptal.com/jwt_claims/is_admin
και η βέλτιστη πρακτική είναι να τοποθετήσετε ένα αρχείο σε αυτήν την τοποθεσία που να περιγράφει την αξίωση, έτσι ώστε να μπορεί να μην γίνεται αναφορά στην τεκμηρίωση.
Ιδιωτικές αξιώσεις
Τα ιδιωτικά ονόματα αξιώσεων μπορούν να χρησιμοποιηθούν σε μέρη όπου τα JWT ανταλλάσσονται μόνο σε κλειστό περιβάλλον μεταξύ γνωστών συστημάτων, όπως μέσα σε μια επιχείρηση. Πρόκειται για ισχυρισμούς που μπορούμε να ορίσουμε, όπως αναγνωριστικά χρήστη, ρόλους χρήστη ή οποιαδήποτε άλλη πληροφορία.
Η χρήση ονομάτων αξιώσεων που ενδέχεται να έχουν αντικρουόμενες σημασιολογικές έννοιες εκτός κλειστού ή ιδιωτικού συστήματος υπόκεινται σε σύγκρουση, οπότε χρησιμοποιήστε τα με προσοχή.
Είναι σημαντικό να σημειωθεί ότι θέλουμε να διατηρήσουμε ένα διακριτικό ιστού όσο το δυνατόν μικρότερο, επομένως χρησιμοποιήστε μόνο τα απαραίτητα δεδομένα σε δημόσιες και ιδιωτικές αξιώσεις.
Παράδειγμα ωφέλιμου φορτίου JWT
{ 'iss': 'toptal.com', 'exp': 1426420800, 'https://www.toptal.com/jwt_claims/is_admin': true, 'company': 'ApeeScape', 'awesome': true }
Αυτό το παράδειγμα ωφέλιμου φορτίου έχει δύο καταχωρημένες αξιώσεις, μία δημόσια αξίωση και δύο ιδιωτικές αξιώσεις. Μόλις κωδικοποιηθεί base64, έχουμε το δεύτερο μέρος του JWT μας.
eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0
Το πρότυπο JWT ακολουθεί την προδιαγραφή JSON Web Signature (JWS) για τη δημιουργία του τελικού υπογεγραμμένου διακριτικού. Δημιουργείται συνδυάζοντας την κωδικοποιημένη JWT Header και την κωδικοποιημένη JWT Payload και υπογράφοντάς την χρησιμοποιώντας έναν ισχυρό αλγόριθμο κρυπτογράφησης, όπως το HMAC SHA-256. Το μυστικό κλειδί της υπογραφής κρατάει ο διακομιστής, οπότε θα μπορεί να επαληθεύει τα υπάρχοντα διακριτικά και να υπογράφει νέα.
$encodedContent = base64UrlEncode(header) + '.' + base64UrlEncode(payload); $signature = hashHmacSHA256($encodedContent);
Αυτό μας δίνει το τελευταίο μέρος του JWT μας.
yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw
Είναι σημαντικό να χρησιμοποιήσετε το TLS / SSL σε συνδυασμό με το JWT, για να αποτρέψετε επιθέσεις man-in-the-middle. Στις περισσότερες περιπτώσεις, αυτό θα είναι αρκετό για την κρυπτογράφηση του ωφέλιμου φορτίου JWT εάν περιέχει ευαίσθητες πληροφορίες. Ωστόσο, εάν θέλουμε να προσθέσουμε ένα επιπλέον επίπεδο προστασίας, μπορούμε να κρυπτογραφήσουμε το ίδιο το ωφέλιμο φορτίο JWT χρησιμοποιώντας το Κρυπτογράφηση Ιστού JSON (PLAY) προδιαγραφή.
Φυσικά, εάν θέλουμε να αποφύγουμε την πρόσθετη επιβάρυνση της χρήσης JWE, μια άλλη επιλογή είναι απλώς να διατηρήσουμε ευαίσθητες πληροφορίες στη βάση δεδομένων μας και να χρησιμοποιήσουμε το διακριτικό μας για πρόσθετες κλήσεις API στον διακομιστή όποτε χρειαζόμαστε πρόσβαση σε ευαίσθητα δεδομένα.
Προτού μπορέσουμε να δούμε όλα τα οφέλη από τη χρήση ελέγχου ταυτότητας JWT, πρέπει να εξετάσουμε τον τρόπο με τον οποίο έγινε έλεγχος ταυτότητας στο παρελθόν.
Επειδή το πρωτόκολλο HTTP είναι ανιθαγενές, πρέπει να υπάρχει ένας μηχανισμός αποθήκευσης πληροφοριών χρήστη και ένας τρόπος ελέγχου ταυτότητας του χρήστη σε κάθε επόμενο αίτημα μετά τη σύνδεση. Οι περισσότεροι ιστότοποι χρησιμοποιούν cookie για την αποθήκευση του αναγνωριστικού περιόδου σύνδεσης χρήστη.
Πως δουλεύει
Το πρόγραμμα περιήγησης υποβάλλει ένα αίτημα POST στον διακομιστή που περιέχει την ταυτότητα και τον κωδικό πρόσβασης του χρήστη. Ο διακομιστής αποκρίνεται με ένα cookie, το οποίο έχει ρυθμιστεί στο πρόγραμμα περιήγησης του χρήστη και περιλαμβάνει ένα αναγνωριστικό περιόδου σύνδεσης για την αναγνώριση του χρήστη.
Σε κάθε επόμενο αίτημα, ο διακομιστής πρέπει να βρει αυτήν την περίοδο σύνδεσης και να την αποεπιλέξει, επειδή τα δεδομένα χρήστη αποθηκεύονται στον διακομιστή.
Δύσκολο να κλιμακωθεί : Ο διακομιστής πρέπει να δημιουργήσει μια περίοδο λειτουργίας για έναν χρήστη και να τον διατηρήσει κάπου στον διακομιστή. Αυτό μπορεί να γίνει στη μνήμη ή σε μια βάση δεδομένων. Εάν διαθέτουμε ένα κατανεμημένο σύστημα, πρέπει να βεβαιωθούμε ότι χρησιμοποιούμε ξεχωριστό χώρο αποθήκευσης συνεδρίας που δεν είναι συνδεδεμένος με το διακομιστή εφαρμογών.
Κοινή χρήση αιτημάτων πολλαπλής προέλευσης (CORS) : Όταν χρησιμοποιείτε κλήσεις AJAX για ανάκτηση πόρου από άλλο τομέα ('cross-origin'), ενδέχεται να αντιμετωπίσουμε προβλήματα με απαγορευμένα αιτήματα, επειδή, από προεπιλογή, τα αιτήματα HTTP δεν περιλαμβάνουν cookie για αιτήματα πολλαπλής προέλευσης.
Σύζευξη με το διαδικτυακό πλαίσιο : Όταν χρησιμοποιείτε έλεγχο ταυτότητας βάσει διακομιστή, είμαστε συνδεδεμένοι με το σχήμα ελέγχου ταυτότητας του πλαισίου μας. Είναι πολύ δύσκολο, ή ακόμα και αδύνατο, να μοιράζεστε δεδομένα συνεδρίας μεταξύ διαφορετικών πλαισίων ιστού γραμμένων σε διαφορετικές γλώσσες προγραμματισμού.
Ο έλεγχος ταυτότητας βάσει διακριτικών / JWT είναι ανιθαγενής, επομένως δεν υπάρχει ανάγκη αποθήκευσης πληροφοριών χρήστη στη συνεδρία. Αυτό μας δίνει τη δυνατότητα κλιμάκωσης της εφαρμογής μας χωρίς να ανησυχείτε για το πού έχει συνδεθεί ο χρήστης. Μπορούμε εύκολα να χρησιμοποιήσουμε το ίδιο διακριτικό για τη λήψη ασφαλούς πόρου από έναν τομέα διαφορετικό από αυτόν στον οποίο είμαστε συνδεδεμένοι.
Πώς λειτουργούν τα Διακριτικά Ιστού JSON
Ένα πρόγραμμα περιήγησης ή ένας πελάτης κινητής τηλεφωνίας υποβάλλει αίτημα στον διακομιστή ελέγχου ταυτότητας που περιέχει πληροφορίες σύνδεσης χρήστη. Ο διακομιστής ελέγχου ταυτότητας δημιουργεί ένα νέο διακριτικό πρόσβασης JWT και το επιστρέφει στον πελάτη. Σε κάθε αίτημα σε έναν περιορισμένο πόρο, ο πελάτης στέλνει το διακριτικό πρόσβασης στη συμβολοσειρά ερωτήματος ή Authorization
επί κεφαλής. Στη συνέχεια, ο διακομιστής επικυρώνει το διακριτικό και, εάν είναι έγκυρο, επιστρέφει τον ασφαλή πόρο στον πελάτη.
Ο διακομιστής ελέγχου ταυτότητας μπορεί να υπογράψει το διακριτικό χρησιμοποιώντας οποιαδήποτε ασφαλή μέθοδο υπογραφής. Για παράδειγμα, ένας αλγόριθμος συμμετρικού κλειδιού όπως το HMAC SHA-256 μπορεί να χρησιμοποιηθεί εάν υπάρχει ένα ασφαλές κανάλι για κοινή χρήση του μυστικού κλειδιού μεταξύ όλων των μερών. Εναλλακτικά, ένα ασύμμετρο σύστημα δημόσιου κλειδιού, όπως το RSA, μπορεί επίσης να χρησιμοποιηθεί, εξαλείφοντας την ανάγκη για περαιτέρω κοινή χρήση κλειδιών.
Ανιθαγενής, ευκολότερο να κλιμακωθεί : Το διακριτικό περιέχει όλες τις πληροφορίες για την αναγνώριση του χρήστη, εξαλείφοντας την ανάγκη για την κατάσταση περιόδου σύνδεσης. Εάν χρησιμοποιήσουμε έναν εξισορροπητή φόρτωσης, μπορούμε να μεταφέρουμε τον χρήστη σε οποιονδήποτε διακομιστή, αντί να δεσμευτούμε στον ίδιο διακομιστή στον οποίο συνδεθήκαμε.
Επαναχρησιμοποίηση : Μπορούμε να έχουμε πολλούς ξεχωριστούς διακομιστές, που εκτελούνται σε πολλές πλατφόρμες και τομείς, επαναχρησιμοποιώντας το ίδιο διακριτικό για έλεγχο ταυτότητας του χρήστη. Είναι εύκολο να δημιουργήσετε μια εφαρμογή που μοιράζεται δικαιώματα με άλλη εφαρμογή.
Ασφάλεια JWT : Δεδομένου ότι δεν χρησιμοποιούμε cookie, δεν χρειάζεται να προστατεύσουμε από επιθέσεις πλαστογραφίας αιτήσεων (CSRF). Πρέπει ακόμη να κρυπτογραφήσουμε τα διακριτικά μας χρησιμοποιώντας το JWE εάν πρέπει να βάλουμε ευαίσθητες πληροφορίες σε αυτά και να μεταδώσουμε τα διακριτικά μας μέσω HTTPS για να αποτρέψουμε επιθέσεις man-in-the-middle.
Εκτέλεση : Δεν υπάρχει αναζήτηση από την πλευρά του διακομιστή για να βρείτε και να αποστειρώσετε τη συνεδρία σε κάθε αίτημα. Το μόνο που πρέπει να κάνουμε είναι να υπολογίσουμε το HMAC SHA-256 για να επικυρώσουμε το διακριτικό και να αναλύσουμε το περιεχόμενό του.
βέλτιστες πρακτικές οπτικοποίησης δεδομένων 2015
Σε αυτό το σεμινάριο JWT πρόκειται να δείξω πώς να εφαρμόσω τον βασικό έλεγχο ταυτότητας χρησιμοποιώντας το JSON Web Tokens σε δύο δημοφιλείς τεχνολογίες ιστού: Laravel 5 για τον κώδικα backend και AngularJS για την εφαρμογή Frontend Single Page Application (SPA). (Μπορείτε να βρείτε ολόκληρο το demo εδώ , και τον πηγαίο κώδικα στο αυτό το αποθετήριο GitHub ώστε να μπορείτε να ακολουθήσετε το σεμινάριο.)
Αυτό το παράδειγμα διακριτικού ιστού JSON δεν θα χρησιμοποιεί κανένα είδος κρυπτογράφησης για να διασφαλίσει την εμπιστευτικότητα των πληροφοριών που διαβιβάζονται στις αξιώσεις. Στην πράξη αυτό είναι συχνά εντάξει, επειδή το TLS / SSL κρυπτογραφεί το αίτημα. Ωστόσο, εάν το διακριτικό πρόκειται να περιέχει ευαίσθητες πληροφορίες, όπως τον αριθμό κοινωνικής ασφάλισης του χρήστη, θα πρέπει επίσης να κρυπτογραφηθεί χρησιμοποιώντας το JWE.
Θα χρησιμοποιήσουμε το Laravel για να χειριστούμε την εγγραφή χρηστών, να διατηρήσουμε δεδομένα χρήστη σε μια βάση δεδομένων και να παρέχουμε ορισμένα περιορισμένα δεδομένα που χρειάζονται έλεγχο ταυτότητας για την κατανάλωση της εφαρμογής Angular. Θα δημιουργήσουμε ένα παράδειγμα υποτομέα API για να προσομοιώσουμε την κοινή χρήση πόρων Cross-origin (CORS).
Εγκατάσταση και εκκίνηση έργου
Για να χρησιμοποιήσουμε το Laravel, πρέπει να εγκαταστήσουμε το Συνθέτης διαχειριστής πακέτων στο μηχάνημά μας. Κατά την ανάπτυξη στο Laravel σας συνιστώ να χρησιμοποιήσετε το προσυσκευασμένο 'κουτί' του Vagrant του Laravel Homestead. Μας παρέχει ένα πλήρες περιβάλλον ανάπτυξης ανεξάρτητα από το λειτουργικό μας σύστημα.
Ο ευκολότερος τρόπος για να εκκινήσετε την εφαρμογή JWT Laravel είναι να χρησιμοποιήσετε ένα πακέτο Composer Laravel Installer.
composer global require 'laravel/installer=~1.1'
Τώρα είμαστε όλοι έτοιμοι να δημιουργήσουμε ένα νέο έργο Laravel εκτελώντας laravel new jwt
.
Για οποιεσδήποτε ερωτήσεις σχετικά με αυτήν τη διαδικασία, ανατρέξτε στον επίσημο Τεκμηρίωση Laravel .
Αφού δημιουργήσουμε τη βασική εφαρμογή Laravel 5, πρέπει να ρυθμίσουμε το Homestead.yaml
, το οποίο θα διαμορφώνει τις αντιστοιχίσεις φακέλων και τη διαμόρφωση τομέων για το τοπικό μας περιβάλλον.
Παράδειγμα a Homestead.yaml
αρχείο:
--- ip: '192.168.10.10' memory: 2048 cpus: 1 authorize: /Users/ttkalec/.ssh/public.psk keys: - /Users/ttkalec/.ssh/private.ppk folders: - map: /coding/jwt to: /home/vagrant/coding/jwt sites: - map: jwt.dev to: /home/vagrant/coding/jwt/public - map: api.jwt.dev to: /home/vagrant/coding/jwt/public variables: - key: APP_ENV value: local
Αφού εκκινήσουμε το κουτί Vagrant με το vagrant up
εντολή και συνδεθήκαμε χρησιμοποιώντας vagrant ssh
, μεταβαίνουμε στον προηγούμενο καθορισμένο κατάλογο έργου. Στο παραπάνω παράδειγμα αυτό θα ήταν /home/vagrant/coding/jwt
. Τώρα μπορούμε να τρέξουμε php artisan migrate
εντολή για τη δημιουργία των απαραίτητων πινάκων χρηστών στη βάση δεδομένων μας.
Εγκατάσταση εξαρτήσεων συνθέτη
Ευτυχώς, υπάρχει μια κοινότητα προγραμματιστών που εργάζονται στο Laravel και διατηρούν πολλά υπέροχα πακέτα με τα οποία μπορούμε να επαναχρησιμοποιήσουμε και να επεκτείνουμε την εφαρμογή μας. Σε αυτό το παράδειγμα θα χρησιμοποιήσουμε tymon/jwt-auth
, από τον Sean Tymon, για το χειρισμό διακριτικών από την πλευρά του διακομιστή και barryvdh/laravel-cors
, από τον Barry vd. Heuvel, για το χειρισμό CORS.
jwt-auth
Απαιτήστε το tymon/jwt-auth
πακέτο στο composer.json
και ενημερώστε τις εξαρτήσεις μας.
composer require tymon/jwt-auth 0.5.*
Προσθέστε το JWTAuthServiceProvider
στο app/config/app.php
μας σειρά παρόχων.
'TymonJWTAuthProvidersJWTAuthServiceProvider'
Στη συνέχεια, σε app/config/app.php
αρχείο, κάτω από το aliases
πίνακα, προσθέτουμε το JWTAuth
πρόσοψη.
'JWTAuth' => 'TymonJWTAuthFacadesJWTAuth'
Τέλος, θα θέλαμε να δημοσιεύσουμε το config πακέτο χρησιμοποιώντας την ακόλουθη εντολή: php artisan config: publish tymon / jwt-auth
Τα διακριτικά JSON Web κρυπτογραφούνται χρησιμοποιώντας ένα μυστικό κλειδί. Μπορούμε να δημιουργήσουμε αυτό το κλειδί χρησιμοποιώντας το php artisan jwt:generate
εντολή. Θα τοποθετηθεί μέσα στο config/jwt.php
αρχείο. Στο περιβάλλον παραγωγής, ωστόσο, δεν θέλουμε ποτέ να έχουμε τους κωδικούς πρόσβασης ή τα κλειδιά API μέσα σε αρχεία διαμόρφωσης. Αντ 'αυτού, πρέπει να τις τοποθετήσουμε μέσα σε μεταβλητές περιβάλλοντος διακομιστή και να τις αναφέρουμε στο αρχείο διαμόρφωσης με το env
λειτουργία. Για παράδειγμα:
'secret' => env('JWT_SECRET')
Μπορούμε να μάθουμε περισσότερα για αυτό το πακέτο και όλες τις ρυθμίσεις διαμόρφωσής του στο Github .
κορδονες
Απαιτήστε το barryvdh/laravel-cors
πακέτο στο composer.json
και ενημερώστε τις εξαρτήσεις μας.
composer require barryvdh/laravel-cors [email protected]
Προσθέστε το CorsServiceProvider
στο app/config/app.php
μας σειρά παρόχων.
'BarryvdhCorsCorsServiceProvider'
Στη συνέχεια, προσθέστε το μεσαίο λογισμικό στο app/Http/Kernel.php
.
'BarryvdhCorsMiddlewareHandleCors'
Δημοσίευση της διαμόρφωσης σε τοπικό config/cors.php
αρχείο χρησιμοποιώντας το php artisan vendor:publish
εντολή.
Παράδειγμα a cors.php
διαμόρφωση αρχείου:
return [ 'defaults' => [ 'supportsCredentials' => false, 'allowedOrigins' => [], 'allowedHeaders' => [], 'allowedMethods' => [], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => [], ], 'paths' => [ 'v1/*' => [ 'allowedOrigins' => ['*'], 'allowedHeaders' => ['*'], 'allowedMethods' => ['*'], 'maxAge' => 3600, ], ], ];
Δρομολόγηση και διαχείριση αιτημάτων HTTP
Για λόγους συντομίας, θα βάλω όλο τον κωδικό μου μέσα στο αρχείο rout.php που είναι υπεύθυνο για τη δρομολόγηση του Laravel και την ανάθεση αιτημάτων σε ελεγκτές. Συνήθως δημιουργούμε αποκλειστικούς ελεγκτές για τον χειρισμό όλων των αιτημάτων HTTP και διατηρούμε τον κώδικα αρθρωτό και καθαρό.
Θα φορτώσουμε την προβολή AngularJS SPA χρησιμοποιώντας
Route::get('/', function () { return view('spa'); });
Εγγραφή χρήστη
Όταν κάνουμε ένα POST
αίτημα προς /signup
με όνομα χρήστη και κωδικό πρόσβασης, θα προσπαθήσουμε να δημιουργήσουμε έναν νέο χρήστη και να τον αποθηκεύσουμε στη βάση δεδομένων. Μετά τη δημιουργία του χρήστη, δημιουργείται ένα JWT και επιστρέφεται μέσω απόκρισης JSON.
Route::post('/signup', function () { $credentials = Input::only('email', 'password'); try { $user = User::create($credentials); } catch (Exception $e) { return Response::json(['error' => 'User already exists.'], HttpResponse::HTTP_CONFLICT); } $token = JWTAuth::fromUser($user); return Response::json(compact('token')); });
Είσοδος χρήστη
Όταν κάνουμε ένα POST
αίτημα προς /signin
με όνομα χρήστη και κωδικό πρόσβασης, επαληθεύουμε ότι ο χρήστης υπάρχει και επιστρέφει ένα JWT μέσω της απόκρισης JSON.
Route::post('/signin', function () { $credentials = Input::only('email', 'password'); if ( ! $token = JWTAuth::attempt($credentials)) { return Response::json(false, HttpResponse::HTTP_UNAUTHORIZED); } return Response::json(compact('token')); });
Ανάκτηση περιορισμένου πόρου στον ίδιο τομέα
Μόλις συνδεθεί ο χρήστης, μπορούμε να πάρουμε τον περιορισμένο πόρο. Έχω δημιουργήσει μια διαδρομή /restricted
που προσομοιώνει έναν πόρο που χρειάζεται έναν επικυρωμένο χρήστη. Για να γίνει αυτό, το αίτημα Authorization
Η κεφαλίδα ή η συμβολοσειρά ερωτήματος πρέπει να παρέχει το JWT για επαλήθευση του backend.
Route::get('/restricted', [ 'before' => 'jwt-auth', function () { $token = JWTAuth::getToken(); $user = JWTAuth::toUser($token); return Response::json([ 'data' => [ 'email' => $user->email, 'registered_at' => $user->created_at->toDateTimeString() ] ]); } ]);
Σε αυτό το παράδειγμα, χρησιμοποιώ το jwt-auth
μεσαίο λογισμικό που παρέχεται στο jwt-auth
πακέτο με χρήση 'before' => 'jwt-auth'
. Αυτό το μεσαίο λογισμικό χρησιμοποιείται για να φιλτράρει το αίτημα και να επικυρώσει το διακριτικό JWT. Εάν το διακριτικό δεν είναι έγκυρο, δεν υπάρχει ή έχει λήξει, το μεσαίο λογισμικό θα ρίξει μια εξαίρεση που μπορούμε να πιάσουμε.
Στο Laravel 5, μπορούμε να εντοπίσουμε εξαιρέσεις χρησιμοποιώντας το app/Exceptions/Handler.php
αρχείο. Χρησιμοποιώντας το render
συνάρτηση μπορούμε να δημιουργήσουμε αποκρίσεις HTTP με βάση την εξαγόμενη εξαίρεση.
public function render($request, Exception $e) { if ($e instanceof TymonJWTAuthExceptionsTokenInvalidException) { return response(['Token is invalid'], 401); } if ($e instanceof TymonJWTAuthExceptionsTokenExpiredException) { return response(['Token has expired'], 401); } return parent::render($request, $e); }
Εάν ο χρήστης έχει πιστοποιηθεί και το διακριτικό είναι έγκυρο, μπορούμε να επιστρέψουμε με ασφάλεια τα περιορισμένα δεδομένα στο frontend μέσω JSON.
Ανάκτηση περιορισμένων πόρων από τον υποτομέα API
Στο επόμενο παράδειγμα διακριτικού ιστού JSON, θα ακολουθήσουμε μια διαφορετική προσέγγιση για την επικύρωση διακριτικών. Αντί να χρησιμοποιήσετε jwt-auth
middleware, θα χειριστούμε τις εξαιρέσεις με μη αυτόματο τρόπο. Όταν κάνουμε ένα POST
αίτημα σε διακομιστή API api.jwt.dev/v1/restricted
, υποβάλλουμε αίτημα πολλαπλής προέλευσης και πρέπει να ενεργοποιήσουμε το CORS στο backend. Ευτυχώς, έχουμε ήδη διαμορφώσει CORS στο config/cors.php
αρχείο.
Route::group(['domain' => 'api.jwt.dev', 'prefix' => 'v1'], function () { Route::get('/restricted', function () { try { JWTAuth::parseToken()->toUser(); } catch (Exception $e) { return Response::json(['error' => $e->getMessage()], HttpResponse::HTTP_UNAUTHORIZED); } return ['data' => 'This has come from a dedicated API subdomain with restricted access.']; }); });
Χρησιμοποιούμε το AngularJS ως front-end, βασιζόμενοι στις κλήσεις API προς τον διακομιστή ελέγχου ταυτότητας Laravel για έλεγχο ταυτότητας χρήστη και δείγματα δεδομένων, καθώς και τον διακομιστή API για δεδομένα παραδείγματος πολλαπλής προέλευσης. Μόλις μεταβούμε στην αρχική σελίδα του έργου μας, το backend θα εξυπηρετήσει το resources/views/spa.blade.php
προβολή που θα εκκινήσει την εφαρμογή Angular.
Εδώ είναι η δομή φακέλων της εφαρμογής Angular:
public/ |-- css/ `-- bootstrap.superhero.min.css |-- lib/ |-- loading-bar.css |-- loading-bar.js `-- ngStorage.js |-- partials/ |-- home.html |-- restricted.html |-- signin.html `-- signup.html `-- scripts/ |-- app.js |-- controllers.js `-- services.js
Εκκίνηση της γωνιακής εφαρμογής
spa.blade.php
περιέχει τα γυμνά απαραίτητα για την εκτέλεση της εφαρμογής. Θα χρησιμοποιήσουμε το Twitter Bootstrap για στυλ, μαζί με ένα προσαρμοσμένο θέμα από Μποτάκι . Για να έχουμε κάποια οπτικά σχόλια κατά την πραγματοποίηση μιας κλήσης AJAX, θα χρησιμοποιήσουμε το γωνιακή φόρτωση-ράβδος script, το οποίο παρακολουθεί αιτήματα XHR και δημιουργεί μια γραμμή φόρτωσης. Στην ενότητα κεφαλίδας, έχουμε τα ακόλουθα φύλλα στυλ:
ngStorage
Το υποσέλιδο της σήμανσής μας περιέχει αναφορές σε βιβλιοθήκες, καθώς και τα προσαρμοσμένα σενάρια μας για γωνιακές μονάδες, ελεγκτές και υπηρεσίες.
Authorization
Χρησιμοποιούμε token
βιβλιοθήκη για το AngularJS, για να αποθηκεύσετε μάρκες στον τοπικό χώρο αποθήκευσης του προγράμματος περιήγησης, ώστε να μπορούμε να το στέλνουμε σε κάθε αίτημα μέσω του Toggle navigation JWT Angular example
επί κεφαλής.
Στο περιβάλλον παραγωγής, φυσικά, θα ελαχιστοποιήσαμε και θα συνδυάζαμε όλα τα αρχεία σεναρίων και τα φύλλα στυλ για να βελτιώσουμε την απόδοση.
Έχω δημιουργήσει μια γραμμή πλοήγησης χρησιμοποιώντας το Bootstrap που θα αλλάξει την ορατότητα των κατάλληλων συνδέσμων, ανάλογα με την κατάσταση σύνδεσης του χρήστη. Η κατάσταση σύνδεσης καθορίζεται από την παρουσία ενός app.js
μεταβλητή στο πεδίο εφαρμογής του ελεγκτή.
angular.module('app', [ 'ngStorage', 'ngRoute', 'angular-loading-bar' ]) .constant('urls', { BASE: 'http://jwt.dev:8000', BASE_API: 'http://api.jwt.dev:8000/v1' }) .config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) { $routeProvider. when('/', { templateUrl: 'partials/home.html', controller: 'HomeController' }). when('/signin', { templateUrl: 'partials/signin.html', controller: 'HomeController' }). when('/signup', { templateUrl: 'partials/signup.html', controller: 'HomeController' }). when('/restricted', { templateUrl: 'partials/restricted.html', controller: 'RestrictedController' }). otherwise({ redirectTo: '/' });
Δρομολόγηση
Έχουμε ένα αρχείο με όνομα HomeController
η οποία είναι υπεύθυνη για τη διαμόρφωση όλων των διεπαφών μας.
RestrictedController
Εδώ μπορούμε να δούμε ότι έχουμε ορίσει τέσσερις διαδρομές που διαχειρίζονται είτε Authorization
ή $httpProvider.interceptors.push(['$q', '$location', '$localStorage', function ($q, $location, $localStorage) { return { 'request': function (config) { config.headers = config.headers || {}; if ($localStorage.token) { config.headers.Authorization = 'Bearer ' + $localStorage.token; } return config; }, 'responseError': function (response) { if (response.status === 401 || response.status === 403) { $location.path('/signin'); } return $q.reject(response); } }; }]);
. Κάθε διαδρομή αντιστοιχεί σε μερική προβολή HTML. Έχουμε επίσης ορίσει δύο σταθερές που περιέχουν διευθύνσεις URL για αιτήματα HTTP στο backend.
Αίτημα αναχαιτιστή
Η υπηρεσία $ http του AngularJS μας επιτρέπει να επικοινωνούμε με το backend και να κάνουμε αιτήματα HTTP. Στην περίπτωσή μας θέλουμε να υποκλέψουμε κάθε αίτημα HTTP και να το εισάγουμε με controllers.js
επικεφαλίδα που περιέχει το JWT μας εάν ο χρήστης έχει πιστοποιηθεί. Μπορούμε επίσης να χρησιμοποιήσουμε έναν αναχαιτιστή για να δημιουργήσουμε έναν καθολικό χειριστή σφαλμάτων HTTP. Ακολουθεί ένα παράδειγμα του αναχαιτιστή μας που εισάγει ένα διακριτικό εάν είναι διαθέσιμο στον τοπικό χώρο αποθήκευσης του προγράμματος περιήγησης.
HomeController
Ελεγκτές
Στο RestrictedController
αρχείο, έχουμε ορίσει δύο ελεγκτές για την εφαρμογή μας: HomeController
και Auth
. angular.module('app') .controller('HomeController', ['$rootScope', '$scope', '$location', '$localStorage', 'Auth', function ($rootScope, $scope, $location, $localStorage, Auth) { function successAuth(res) { $localStorage.token = res.token; window.location = '/'; } $scope.signin = function () { var formData = { email: $scope.email, password: $scope.password }; Auth.signin(formData, successAuth, function () { $rootScope.error = 'Invalid credentials.'; }) }; $scope.signup = function () { var formData = { email: $scope.email, password: $scope.password }; Auth.signup(formData, successAuth, function () { $rootScope.error = 'Failed to signup'; }) }; $scope.logout = function () { Auth.logout(function () { window.location = '/' }); }; $scope.token = $localStorage.token; $scope.tokenClaims = Auth.getTokenClaims(); }])
χειρίζεται τη λειτουργία εισόδου, εγγραφής και αποσύνδεσης. Μεταβιβάζει τα δεδομένα ονόματος χρήστη και κωδικού πρόσβασης από τις φόρμες σύνδεσης και εγγραφής στο RestrictedController
υπηρεσία, η οποία στέλνει αιτήματα HTTP στο backend. Στη συνέχεια, αποθηκεύει το διακριτικό στον τοπικό χώρο αποθήκευσης ή εμφανίζει ένα μήνυμα σφάλματος, ανάλογα με την απόκριση από το backend.
getRestrictedData
getApiData
συμπεριφέρεται με τον ίδιο τρόπο, μόνο παίρνει τα δεδομένα χρησιμοποιώντας το Data
και .controller('RestrictedController', ['$rootScope', '$scope', 'Data', function ($rootScope, $scope, Data) { Data.getRestrictedData(function (res) { $scope.data = res.data; }, function () { $rootScope.error = 'Failed to fetch restricted content.'; }); Data.getApiData(function (res) { $scope.api = res.data; }, function () { $rootScope.error = 'Failed to fetch restricted API content.'; }); }]);
λειτουργίες στο Authorization
υπηρεσία.
tokenClaims
Το backend είναι υπεύθυνο για την εξυπηρέτηση των περιορισμένων δεδομένων μόνο εάν ο χρήστης έχει πιστοποιηθεί. Αυτό σημαίνει ότι για να ανταποκριθεί με τα περιορισμένα δεδομένα, το αίτημα για αυτά τα δεδομένα πρέπει να περιέχει ένα έγκυρο JWT μέσα στο getTokenClaims
συμβολοσειρά κεφαλίδας ή ερωτήματος. Εάν αυτό δεν συμβαίνει, ο διακομιστής θα ανταποκριθεί με κωδικό κατάστασης σφάλματος 401 μη εξουσιοδοτημένο.
Υπηρεσία Auth
Η υπηρεσία Auth είναι υπεύθυνη για την υποβολή αιτημάτων σύνδεσης και εγγραφής HTTP στο backend. Εάν το αίτημα είναι επιτυχές, η απόκριση περιέχει το υπογεγραμμένο διακριτικό, το οποίο στη συνέχεια αποκωδικοποιείται base64 και οι συνημμένες πληροφορίες αξιώσεων διακριτικών αποθηκεύονται σε angular.module('app') .factory('Auth', ['$http', '$localStorage', 'urls', function ($http, $localStorage, urls) { function urlBase64Decode(str) { var output = str.replace('-', '+').replace('_', '/'); switch (output.length % 4) { case 0: break; case 2: output += '=='; break; case 3: output += '='; break; default: throw 'Illegal base64url string!'; } return window.atob(output); } function getClaimsFromToken() { var token = $localStorage.token; var user = {}; if (typeof token !== 'undefined') { var encoded = token.split('.')[1]; user = JSON.parse(urlBase64Decode(encoded)); } return user; } var tokenClaims = getClaimsFromToken(); return { signup: function (data, success, error) { $http.post(urls.BASE + '/signup', data).success(success).error(error) }, signin: function (data, success, error) { $http.post(urls.BASE + '/signin', data).success(success).error(error) }, logout: function (success) { tokenClaims = {}; delete $localStorage.token; success(); }, getTokenClaims: function () { return tokenClaims; } }; } ]);
μεταβλητός. Αυτό διαβιβάζεται στον ελεγκτή μέσω του angular.module('app') .factory('Data', ['$http', 'urls', function ($http, urls) { return { getRestrictedData: function (success, error) { $http.get(urls.BASE + '/restricted').success(success).error(error) }, getApiData: function (success, error) { $http.get(urls.BASE_API + '/restricted').success(success).error(error) } }; } ]);
λειτουργία.
|_+_|
Υπηρεσία δεδομένων
Αυτή είναι μια απλή υπηρεσία που υποβάλλει αιτήματα στον διακομιστή ελέγχου ταυτότητας, καθώς και στο διακομιστή API για ορισμένα εικονικά περιορισμένα δεδομένα. Κάνει το αίτημα και μεταβιβάζει επιστροφές επιτυχίας και σφάλματος στον ελεγκτή.
|_+_|
Ο έλεγχος ταυτότητας βάσει κουπονιών μας επιτρέπει να κατασκευάσουμε αποσυνδεδεμένα συστήματα που δεν συνδέονται με ένα συγκεκριμένο σχήμα ελέγχου ταυτότητας. Το διακριτικό μπορεί να δημιουργηθεί οπουδήποτε και να καταναλωθεί σε οποιοδήποτε σύστημα που χρησιμοποιεί το ίδιο μυστικό κλειδί για την υπογραφή του διακριτικού. Είναι έτοιμα για κινητά και δεν απαιτούν τη χρήση cookie.
Τα Διακριτικά Ιστού JSON λειτουργούν σε όλες τις δημοφιλείς γλώσσες προγραμματισμού και κερδίζουν γρήγορα δημοτικότητα. Υποστηρίζονται από εταιρείες όπως η Google, η Microsoft και η Zendesk. Η τυπική προδιαγραφή τους από το Internet Engineering Task Force (IETF) είναι ακόμα στη δοκιμαστική έκδοση και μπορεί να αλλάξει ελαφρώς στο μέλλον.
Υπάρχουν ακόμη πολλά να καλύψουμε σχετικά με τα JWTs, όπως με τον τρόπο χειρισμού του ασφάλεια λεπτομέρειες και αναζωογονητικά διακριτικά όταν λήγουν, αλλά το σεμινάριο JSON Web Token θα πρέπει να αποδεικνύει τη βασική χρήση και, το πιο σημαντικό, τα πλεονεκτήματα της χρήσης JWTs.
Αυτό αναφέρεται σε ένα JWT, το οποίο διαβιβάζεται μέσω της κεφαλίδας HTTP που ονομάζεται Εξουσιοδότηση, με τη μορφή συμβολοσειράς «Bearer $ your_token_here».
Το JWT σημαίνει JSON Web Token, μια κοινή τακτική ελέγχου ταυτότητας που χρησιμοποιείται σε σύγχρονες εφαρμογές ιστού.
Το JSON είναι απλώς μια μορφή δεδομένων που μοιάζει πολύ με την κυριολεκτική μορφή δεδομένων που επιτρέπεται από το JavaScript. Είναι μια ιεραρχική μορφή που επιτρέπει ένθετα αντικείμενα και πίνακες, καθώς και συμβολοσειρά και αριθμητικά γράμματα.