Autentificarea este una dintre cele mai importante părți ale oricărei aplicații web. În acest tutorial, vom discuta despre sistemele de autentificare bazate pe token și despre modul în care acestea diferă de sistemele de autentificare tradiționale. La sfârșitul acestui tutorial, veți vedea o demonstrație complet funcțională scrisă în AngularJS și NodeJS.
Puteți găsi, de asemenea, o gamă largă de scripturi și aplicații de autentificare autentice pe Envato Market, cum ar fi:
Sau, dacă vă confruntați cu un bug în codul dvs. AngularJS, îl puteți trimite la araneux pe Envato Studio pentru al stabili.
Înainte de a continua cu un sistem de autentificare bazat pe token, să aruncăm o privire mai întâi la un sistem tradițional de autentificare.
Totul este bine până în acest moment. Aplicația web funcționează bine și este capabilă să autentifice utilizatorii astfel încât aceștia să poată accesa obiective finite; cu toate acestea, ce se întâmplă atunci când doriți să dezvoltați un alt client, de exemplu pentru Android, pentru aplicația dvs.? Veți putea utiliza aplicația curentă pentru autentificarea clienților mobili și pentru difuzarea de conținut restricționat? În prezent, nu. Există două motive principale pentru aceasta:
În acest caz, aveți nevoie de o aplicație independentă de client.
În autentificarea bazată pe token, cookie-urile și sesiunile nu vor fi utilizate. Un jeton va fi folosit pentru autentificarea unui utilizator pentru fiecare cerere către server. Să reproiectăm primul scenariu cu autentificare bazată pe token.
Acesta va folosi următorul flux de control:
În acest caz, nu avem sesiune sau cookie returnate și nu am returnat niciun conținut HTML. Aceasta înseamnă că putem folosi această arhitectură pentru orice client pentru o aplicație specifică. Puteți vedea schema de arhitectură de mai jos:
Deci, ce este acest JWT??
JWT înseamnă JSON Web Token și este un format token utilizat în anteturile de autorizare. Acest simbol vă ajută să proiectați comunicarea între două sisteme într-un mod sigur. Să reformulăm JWT ca "jeton purtător" pentru scopurile acestui tutorial. Titlul unui purtător constă din trei părți: antetul, sarcina utilă și semnătura.
Puteți vedea schema JWT și un jeton de mai jos;
Nu este nevoie să implementați generatorul de jetoane la purtător, deoarece puteți găsi versiuni care există deja în mai multe limbi. Puteți vedea câteva dintre acestea:
Limba | Adresa URL a bibliotecii |
---|---|
NodeJS | http://github.com/auth0/node-jsonwebtoken |
PHP | http://github.com/firebase/php-jwt |
Java | http://github.com/auth0/java-jwt |
Rubin | http://github.com/progrium/ruby-jwt |
.NET | http://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet |
Piton | http://github.com/progrium/pyjwt/ |
După ce am acoperit câteva informații de bază despre autentificarea bazată pe token, putem continua cu un exemplu practic. Uitați-vă la următoarea schemă, după care o vom analiza mai detaliat:
https://api.yourexampleapp.com
. Dacă o mulțime de utilizatori utilizează aplicația, este posibil ca mai multe servere să fie obligate să deservească operația solicitată.https://api.yourexampleapp.com
, mai întâi balanța de încărcare va rezolva o cerere și apoi va redirecționa clientul către un anumit server.https://api.yourexampleapp.com
, aplicația back-end va intercepta antetul solicitării și va extrage informațiile token din antetul de autorizare. O interogare bazei de date se va face folosind acest jeton. Dacă acest token este valabil și are permisiunea necesară pentru a accesa punctul final solicitat, acesta va continua. Dacă nu, va returna un cod de răspuns 403 (care indică o stare interzisă).Autentificarea bazată pe autentificarea prin autentificare are mai multe avantaje care rezolvă probleme serioase. Unele dintre ele sunt după cum urmează:
temp
, cel puțin pentru prima dată. Să presupunem că aveți mai multe servere și că este creată o sesiune pe primul server. Atunci când faceți o altă solicitare și solicitarea dvs. cade într-un alt server, informațiile despre sesiune nu vor exista și vor primi un răspuns "neautorizat". Știu, puteți rezolva asta cu o sesiune lipicioasă. Cu toate acestea, în autentificarea bazată pe token, acest caz este rezolvat în mod natural. Nu există o problemă de sesiune lipicioasă, deoarece tokenul de solicitare este interceptat la fiecare solicitare de pe orice server.Acestea sunt cele mai comune avantaje ale autentificării și comunicării bazate pe token. Acesta este sfârșitul discuțiilor teoretice și arhitecturale despre autentificarea bazată pe token. Timp pentru un exemplu practic.
Veți vedea două aplicații pentru a demonstra autentificarea bazată pe token:
În cadrul proiectului back-end, vor exista implementări de servicii, iar rezultatele serviciului vor fi în format JSON. Nu există nici o vizită returnată în servicii. În proiectul de front-end, va exista un proiect AngularJS pentru front-end HTML și apoi aplicația front-end va fi populată de serviciile AngularJS pentru a face cereri către serviciile back-end.
În proiectul back-end, există trei fișiere principale:
package.json
este pentru managementul dependenței.modele \ user.js
conține un model de utilizator care va fi utilizat pentru a face operațiuni baze de date despre utilizatori.server.js
este pentru bootstrapping de proiect și manipularea cererii.Asta e! Acest proiect este foarte simplu, astfel încât să înțelegeți cu ușurință conceptul principal fără a face o scufundare profundă.
"nume": "angular-restful-auth", "versiune": "0.0.1", "dependențe" , "morgan": "ultimul", "mongoose": "3.8.8", "jsonwebtoken": "0.4.0", "motoare": "node": "> = 0.10.0"
package.json
conține dependențe pentru proiect: expres
pentru MVC, corp-parser
pentru simularea manipulării post-cerere în NodeJS, morgan
pentru înregistrarea solicitărilor, mangustă
pentru ca cadrul nostru ORM să se conecteze la MongoDB, și jsonwebtoken
pentru crearea jetoanelor JWT utilizând modelul nostru de utilizator. Există, de asemenea, un atribut numit motoare
care spune că acest proiect este realizat utilizând versiunea NodeJS> = 0.10.0. Acest lucru este util pentru serviciile PaaS precum Heroku. Vom aborda, de asemenea, acest subiect într-o altă secțiune.
var mongoose = necesită ("mongoose"); var Schema = mongoose.Scema; var UserSchema = schema nouă (email: String, parola: String, token: String); module.exports = mongoose.model ("Utilizator", UserSchema);
Am spus că vom genera un jeton utilizând sarcina utilă a modelului utilizator. Acest model ne ajută să facem operațiuni de utilizator pe MongoDB. În user.js
, schema de utilizator este definită și modelul Utilizator este creat utilizând un model de mongoasă. Acest model este gata pentru operațiunile bazei de date.
Dependințele noastre sunt definite și modelul nostru de utilizatori este definit, așa că acum să combinăm toate cele pentru a construi un serviciu pentru tratarea cererilor specifice.
// Modulele necesare var express = necesită ("expres"); var morgan = necesită ("morgan"); var bodyParser = necesită ("body-parser"); var jwt = necesită ("jsonwebtoken"); var mongoose = necesită ("mongoose"); var app = expres ();
În NodeJS, puteți include un modul în proiect utilizând necesita
. În primul rând, trebuie să importăm modulele necesare în proiect:
var port = process.env.PORT || 3001; var User = solicită ('./ models / User'); // Conectați-vă la DB mongoose.connect (process.env.MONGO_URL);
Serviciul nostru va servi printr-un port specific. Dacă orice variabilă de port este definită în variabilele sistemului de sistem, puteți folosi acea variabilă port sau avem port definit 3001
. După aceasta, modelul Utilizator este inclus, iar conexiunea bazei de date este stabilită pentru a face anumite operații de utilizator. Nu uitați să definiți o variabilă de mediu-MONGO_URL
-pentru adresa URL a conexiunii bazei de date.
app.use (bodyParser.urlencoded (extins: true)); app.use (bodyParser.json ()); app.use (morgan ( "dev")); app.use (funcția (req, res, next) res.setHeader ('Access-Control-Allow-Origine', '*'); '), res.setHeader (' Access-Control-Allow-Headers ',' X-Requested-With, Content-type, Autorizare ');
În secțiunea de mai sus, am făcut câteva configurații pentru a simula o manipulare a cererilor HTTP în NodeJS utilizând Express. Permitem solicitările să vină din domenii diferite pentru a dezvolta un sistem independent de client. Dacă nu permiteți acest lucru, veți declanșa o eroare CORS (partajarea cererii de origine încrucișată) în browserul web.
Access-Control-Allow-Origine
permis pentru toate domeniile.POST
și OBȚINE
solicită acest serviciu.X-solicitat-Cu
și tipul de conținut
anteturile sunt permise.user_fire (email: req.body.email, parola: req.body.password, funcția (err, user) if (err) res.json (tip: false, date: "Eroare apărută:" + err); altceva if (utilizator) res.json (type: true, data: user, token: user.token); altceva res.json (tip: false, date: "E-mail incorect / parola");););
Am importat toate modulele necesare și ne-am definit configurația, așa că acum este timpul să definim persoanele care solicită acest lucru. În codul de mai sus, ori de câte ori faceți POST
cererea de a /autentifica
cu nume de utilizator și parolă, veți obține o JWT
jeton. În primul rând, interogarea bazei de date este procesată utilizând un nume de utilizator și o parolă. Dacă există un utilizator, datele utilizatorului vor fi returnate cu jetonul. Dar, dacă nu există un astfel de utilizator care să se potrivească cu numele de utilizator și / sau parola?
if (err) (login), function (req, res) user.findOne res.json (tip: false, date: "Eroare a apărut:" + err); altceva if (utilizator) res.json ( altfel var userModel = utilizator nou (); userModel.email = req.body.email; userModel.password = req.body.password; userModel.save (functie (err, user) user.token = jwt.sign , process.env.JWT_SECRET); user.save (funcția (err, user1) res.json (type: true, data: user1, token: user1.token);); );
Când faci a POST
cererea de a /conectare
cu numele de utilizator și parola, un nou utilizator va fi creat utilizând informațiile postate de utilizator. Pe 19
line, puteți vedea că un nou simbol JSON este generat utilizând jsonwebtoken
modulul care a fost atribuit JWT
variabil. Partea de autentificare este OK. Ce se întâmplă dacă încercăm să accesăm un obiectiv final restricționat? Cum putem reuși să accesăm acest punct final?
Aplicația ('/ me', ensureAuthorized, funcția (req, res) User.findOne (token: req.token, funcția (err, user) if (err) res.json , date: "Eroare a apărut:" + err); altceva res.json (type: true, data: user);););
Când faci a OBȚINE
cererea de a /pe mine
, veți obține informațiile despre utilizatorul curent, dar pentru a continua cu punctul final solicitat, ensureAuthorized
funcția va fi executată.
funcția ensureAuthorized (req, res, next) var bearerToken; var bearerHeader = req.headers ["autorizație"]; dacă (tipul bearerHeader! == 'undefined') var bearer = bearerHeader.split (""); bearerToken = purtător [1]; req.token = bearerToken; Următor →(); altceva res.send (403);
În această funcție, antetele de cerere sunt interceptate și autorizare
antetul este extras. Dacă există un jeton la purtător în acest antet, acel jeton este atribuit req.token
pentru a fi utilizate pe parcursul cererii, iar cererea poate fi continuată prin utilizarea Următor →()
. Dacă un token nu există, veți primi un răspuns 403 (interzis). Să ne întoarcem la manipulator /pe mine
, si foloseste req.token
pentru a prelua datele de utilizator cu acest jeton. Ori de câte ori creați un utilizator nou, se generează și se salvează un token în modelul de utilizator din DB. Aceste jetoane sunt unice.
Avem doar trei manageri pentru acest proiect simplu. După aceea, veți vedea;
process.on ('uncaughtException', funcția (err) console.log (err););
Aplicația NodeJS se poate prăbuși dacă apare o eroare. Cu codul de mai sus, acel accident este împiedicat și un jurnal de eroare este tipărit în consola. În final, putem porni serverul utilizând următorul fragment de cod.
// Porniți serverul app.listen (port, funcție () console.log ("Ascultarea serverului Express pe port" +););
În concluzie:
Am terminat serviciul back-end. Pentru ca acesta să poată fi utilizat de mai mulți clienți, puteți implementa această aplicație de server simplu pe serverele dvs. sau poate puteți implementa în Heroku. Există un fișier numit Procfile
în dosarul rădăcină al proiectului. Să ne desfășurăm serviciul în Heroku.
Puteți clona proiectul din spate din acest depozit GitHub.
Nu voi discuta cum să creezi o aplicație în Heroku; puteți consulta acest articol pentru a crea o aplicație Heroku dacă nu ați făcut acest lucru înainte. După ce creați aplicația dvs. Heroku, puteți adăuga o destinație la proiectul dvs. curent utilizând următoarea comandă:
git remote add heroku
Acum ați clonat un proiect și ați adăugat o destinație. După adăugați git
și git comite
, puteți să vă împingeți codul la Heroku efectuând git push master heroku
. Când împingeți cu succes un proiect, Heroku va efectua npm install
comanda pentru a descărca dependențele în temp
dosar pe Heroku. După aceasta, va porni aplicația dvs. și puteți accesa serviciul dvs. utilizând protocolul HTTP.
În proiectul front-end, veți vedea un proiect AngularJS. Aici, voi menționa numai secțiunile principale din proiectul front-end, deoarece AngularJS nu este ceva care poate fi acoperit într-un singur tutorial.
Puteți clona proiectul din acest depozit GitHub. În acest proiect, veți vedea următoarea structură de directoare:
ngStorage.js
este o bibliotecă pentru AngularJS pentru a manipula operațiunile de stocare locală. De asemenea, există un aspect principal index.html
și partiale care extind aspectul principal sub amprente parțiale
pliant. controllers.js
este pentru definirea acțiunilor controlerului nostru în front-end. services.js
este pentru a face cereri de servicii pentru serviciul nostru pe care l-am menționat în proiectul anterior. Avem un fișier numit bootstrap app.js
iar în acest fișier se aplică configurațiile și importurile de module. In cele din urma, client.js
este pentru a servi fișiere HTML statice (sau doar index.html
, în acest caz); acest lucru ne ajută să furnizăm fișiere statice HTML atunci când implementați pe un server fără a utiliza Apache sau alte servere web.
...
În fișierul HTML cu structură principală, toate fișierele JavaScript necesare sunt incluse pentru bibliotecile legate de AngularJS, precum și pentru controlerul nostru personalizat, serviciul și fișierul de aplicații.
"utilizarea strictă"; / * Controlere * / angular.module ('angularRestfulAuth') .controller ('HomeCtrl', '$ rootScope', '$ scope', '$ location', ' $ scope scope, $ locație, $ localStorage, Main) $ scope.signin = funcție () var formData = email: $ scope.email, password: $ scope.password dacă res.type == false) alert (res.data) altceva $ localStorage.token = res.data.token; window.location = "/";, funcția () $ rootScope.error = '$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ res.type == false) alert (res.data) altceva $ localStorage.token = res.data.token; window.location = "/", funcția () $ rootScope.error = () ($) $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $; ; $ scope.logout = function () Main.logout (fu nction () window.location = "/", funcția () alert ("Nu sa putut logout!"); ); ; $ scope.token = $ localStorage.token; ])
În codul de mai sus, HomeCtrl
controlerul este definit și unele module necesare sunt injectate ca $ rootScope
și domeniul de aplicare $
. Injecția de dependență este una dintre cele mai puternice proprietăți ale AngularJS. domeniul de aplicare $
este variabila de punte între controale și vederi în AngularJS ceea ce înseamnă că puteți folosi Test
în vedere dacă l-ați definit într-un controler specificat $ Scope.test = ...
În acest controler sunt definite câteva funcții utilitare, cum ar fi:
conectare
pentru a configura un buton de conectare pe formularul de conectareInscrie-te
pentru manipularea formularului de înscrierepe mine
pentru alocarea butonului Me în layoutÎn structura principală, în lista de meniuri principale, puteți să vedeți date-ng-controler
atribut cu valoare HomeCtrl
. Asta înseamnă că acest meniu dom
elementul poate împărtăși domeniul de aplicare cu HomeCtrl
. Când faceți clic pe butonul de înscriere în formular, se va executa funcția de înscriere în fișierul controlerului și în această funcție serviciul de înscriere va fi utilizat de la Principal
care este deja injectat în acest controler.
Structura principală este vizualizați -> controler -> serviciu
. Acest serviciu face simple solicitări Ajax la back-end pentru a obține date specifice.
"utilizarea strictă"; Angular (), funcția ('http', 'localStorage'), funcția ($ http, $ localStorage) var baseUrl = "your_service_url", funcția changeUser (utilizator) angular. (')', '(', '/'); comuta (output.length% 4) caz 0: pauză; cazul 2: ieșire + = '=='; pauză; cazul 3: ieșire + = '='; funcția getUserFromToken () var token = $ localStorage.token; var user = ; dacă (token tip! == 'undefined') var encoded = token.split ('.') [1]; parse (urlBase64Decode (codificat)); return utilizator; var currentUser = getUserFromToken (); return save: functie (date, succes, eroare) $ http.post (baseUrl + succes (), eroare (error), login: function (date, succes, eroare) $ http.post (baseUrl + succes, eroare) $ htt p.get (baseUrl + '/me').success(success).error(error), logout: funcția (succes) changeUser (); ștergeți $ localStorage.token; succes(); ; ]);
În codul de mai sus, puteți vedea funcții de serviciu cum ar fi efectuarea de cereri de autentificare. În controller.js, este posibil să fi realizat deja că există funcții precum Main.me
. Acest Principal
serviciul a fost injectat în controler, iar în operator, serviciile care aparțin acestui serviciu sunt chemați direct.
Aceste funcții sunt pur și simplu solicitări Ajax către serviciul nostru pe care l-am desfășurat împreună. Nu uitați să introduceți adresa URL a serviciului baseUrl
în codul de mai sus. Atunci când desfășurați serviciul dvs. la Heroku, veți primi un URL de serviciu cum ar fi appname.herokuapp.com
. În codul de mai sus, veți seta var baseUrl = "appname.herokuapp.com"
.
În partea de înscriere sau conectare a aplicației, tokenul purtătorului răspunde solicitării și acest jeton este salvat în spațiul de stocare local. Ori de câte ori faceți o cerere la un serviciu în back-end, trebuie să puneți acest jeton în anteturi. Puteți face acest lucru folosind interceptoarele AngularJS.
($ q, $ location, $ localStorage) return 'request': funcția (config) config.headers = config.headers || , dacă ($ localStorage.token) config.headers.Authorization = 'Bearer' + $ localStorage.token; return config;, 'responseError': funcția (răspunsul) if (răspuns. status === 401 || răspuns.status === 403) $ loc.path ('/ signin'); return $ q.reject (răspuns);;]);
În codul de mai sus, fiecare cerere este interceptată, iar antetul și valoarea de autorizare sunt plasate în antete.
În proiectul front-end, avem câteva pagini parțiale cum ar fi conectare
, Inscrie-te
, detaliile profilului
, și vb
. Aceste pagini parțiale sunt legate de controale specifice. Puteți vedea acea relație în app.js
:
"$ routeProvider", "$ httpProvider", functie ($ routeProvider, $ httpProvider) $ routeProvider. atunci când ('/', null ' templateUrl: 'partials / home.html', controler: 'HomeCtrl') când ('/ signin', templateUrl: 'partials / ', templateUrl:' partials / me.html ', controler:' HomeCtrl ')), în caz contrar ( redirectTo: '/');
După cum puteți înțelege cu ușurință în codul de mai sus, atunci când mergeți la /
, home.html
pagina va fi redată. Alt exemplu: dacă te duci la /Inscrie-te
, signup.html
va fi redat. Această operație de redare va fi efectuată în browser, nu pe partea de server.
Puteți vedea cum tot ceea ce am discutat în acest tutorial funcționează în practică, verificând acest demo de lucru.
Sistemul de autentificare pe bază de token vă ajută să construiți un sistem de autentificare / autorizare în timp ce dezvoltați servicii independente de client. Prin utilizarea acestei tehnologii, vă veți concentra pe serviciile (sau API-urile).
Partea de autentificare / autorizare va fi gestionată de sistemul de autentificare bazat pe token drept un strat în fața serviciilor dvs. Puteți accesa și utiliza serviciile de la orice client, cum ar fi browserele web, Android, iOS sau un client desktop.
Și dacă căutați soluții gata făcute, verificați scripturile de autentificare și aplicațiile de pe Envato Market.