Крипто валута за почетнике: Битцоин и даље
Наука О Подацима И Базе Података
Данас ћемо погледати како је лако интегрисати ЈСОН веб токен (ЈВТ) аутентичност у ваш Угаона 6 (или новија) апликација на једној страници (СПА). Почнимо са мало позадине.
Овде је најлакши и најсажетији одговор да су прикладни, компактни и сигурни. Погледајмо те тврдње детаљно:
На шта се све ово своди је да имате сигуран и ефикасан начин за аутентификацију корисника, а затим верификацију позива на ваше АПИ крајње тачке без потребе за рашчлањивањем било каквих структура података нити за применом сопствене енкрипције.
Дакле, са мало позадине, сада можемо заронити у то како би ово функционисало у стварној апликацији. За овај пример претпоставићу да имамо Ноде.јс сервер који хостује наш АПИ, а ми јесмо развијање СПА све листе користе Угаона 6. Хајде да радимо и са овом АПИ структуром:
предности вештачке интелигенције
/auth
→ POST
(објавите корисничко име и лозинку за потврду идентитета и примање ЈВТ-а) /todos
→ GET
(вратите листу свих ставки листе корисника) /todos/{id}
→ GET
(вратите одређену ставку листе задатака) /users
→ GET
(враћа листу корисника) Ускоро ћемо проћи кроз стварање ове једноставне апликације, али за сада се концентришимо на интеракцију у теорији. Имамо једноставну страницу за пријављивање, где корисник може да унесе своје корисничко име и лозинку. Када се образац преда, он шаље те информације на /auth
крајња тачка. Ноде сервер тада може да аутентификује корисника на било који начин који одговара (тражење базе података, постављање упита другој веб услузи итд.), Али на крају крајња тачка мора да врати ЈВТ.
ЈВТ за овај пример садржи неколико резервисана потраживања , а неки приватна потраживања . Резервисана потраживања су једноставно парови кључ / вредност које препоручује ЈВТ, а који се обично користе за потврду идентитета, док су приватна потраживања парови парови кључ / вредност применљиви само на нашу апликацију:
Резервисани захтеви
iss
: Издавач овог токена. Типично је ФКДН сервера, али може бити било шта све док клијентска апликација зна да то очекује.exp
: Датум и време истека овог токена. Ово је у секундама од поноћи 01. јануара 1970 ГМТ (Уник време). nbf
: Не важи пре временске ознаке. Не користи се често, али даје доњу границу за период важења. Исти формат као exp
. Приватни захтеви
uid
: Усер ИД пријављеног корисника.role
: Улога додељена пријављеном кориснику.Наше информације ће бити кодиране у основи 64 и потписане помоћу ХМАЦ-а заједничким кључем todo-app-super-shared-secret
. Испод је пример како ЈВТ изгледа:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b2RvYXBpIiwibmJmIjoxNDk4MTE3NjQyLCJleHAiOjE0OTgxMjEyNDIsInVpZCI6MSwicm9sZSI6ImFkbWluIn0.ZDz_1vcIlnZz64nSM28yA1s-4c_iw3Z2ZtP-SgcYRPQ
Ово стринг је све што нам је потребно да бисмо били сигурни да имамо ваљану пријаву, да бисмо знали који је корисник повезан и да бисмо знали чак и које улоге корисник има.
Већина библиотека и апликација наставља да складишти овај ЈВТ у localStorage
или sessionStorage
за лако проналажење, али ово је само уобичајена пракса. Шта ћете радити са токеном, зависи од вас, под условом да га можете обезбедити за будуће АПИ позиве.
Сада, кад год СПА жели да упути позив било којој од заштићених крајњих тачака АПИ-ја, једноставно мора да пошаље токен у Authorization
ХТТП заглавље.
Authorization: Bearer {JWT Token}
Белешка : Још једном, ово је једноставно уобичајена пракса. ЈВТ не прописује ниједан одређени метод за само слање на сервер. Можете га додати и УРЛ-у или послати у колачићу.
Једном када сервер прими ЈВТ, он га може декодирати, осигурати доследност користећи заједничку тајну ХМАЦ-а и проверити истек помоћу exp
и nbf
поља. Такође може користити iss
поље како би се осигурало да је првобитна издавалачка страна овог ЈВТ-а.
Једном када се сервер задовољи ваљаношћу токена, могу се користити информације ускладиштене унутар ЈВТ-а. На пример, uid
који смо укључили даје нам ИД корисника који подноси захтев. За овај конкретни пример такође смо укључили role
поље, које нам омогућава да доносимо одлуке о томе да ли корисник треба да може да приступи одређеној крајњој тачки или не. (Да ли верујете овим информацијама или радије желите да претражите базу података зависи од потребног нивоа сигурности.)
function getTodos(jwtString) { var token = JWTDecode(jwtstring); if( Date.now() token.exp*1000) { throw new Error('Token has expired'); } if( token.iss != 'todoapi') { throw new Error('Token not issued here'); } var userID = token.uid; var todos = loadUserTodosFromDB(userID); return JSON.stringify(todos); }
Да бисте наставили даље, мораћете да имате инсталирану новију верзију Ноде.јс (6.к или новија), нпм (3.к или новија) и ангулар-цли. Ако требате да инсталирате Ноде.јс, који укључује нпм, следите упутства овде . После angular-cli
може се инсталирати помоћу npm
(или yarn
, ако сте га инсталирали):
# installation using npm npm install -g @angular/cli # installation using yarn yarn global add @angular/cli
Нећу улазити у детаље о узорку Ангулар 6 који ћемо овде користити, али за следећи корак сам створио спремиште Гитхуб у којем се налази мала тодо апликација која илуструје једноставност додавања ЈВТ потврде идентитета у вашу апликацију. Једноставно га клонирајте користећи следеће:
git clone https://github.com/sschocke/angular-jwt-todo.git cd angular-jwt-todo git checkout pre-jwt
Тхе git checkout pre-jwt
наредба се пребацује на именовано издање тамо гдје ЈВТ није имплементиран.
Унутар би требало да постоје две фасцикле под називом server
и client
. Сервер је Ноде АПИ сервер који ће угостити наш основни АПИ. Клијент је наша апликација Ангулар 6.
Да бисте започели, инсталирајте зависности и покрените АПИ сервер.
cd server # installation using npm npm install # or installation using yarn yarn node app.js
Требали бисте бити у могућности да пратите ове везе и добијете ЈСОН представу података. За сада, док нисмо проверили идентитет, чврсто смо кодирали /todos
крајња тачка за враћање задатака за userID=1
:
како се користи шаблон за покретање
userID=1
Да бисмо започели са клијентском апликацијом, такође морамо инсталирати зависности и покренути дев сервер.
cd client # using npm npm install npm start # using yarn yarn yarn start
Белешка : У зависности од брзине ваше линије, потребно је неко време да преузмете све зависности.
Ако све иде како треба, требало би да видите нешто слично приликом навигације до хттп: // лоцалхост: 4200 :
Да бисмо додали подршку за ЈВТ аутентификацију, користићемо неке стандардне библиотеке које то чине једноставнијим. Можете се, наравно, одрећи ових погодности и све применити сами, али то је изван нашег делокруга овде.
Прво, инсталирајмо библиотеку на страни клијента. Развио га је и одржава Аутх0 , која је библиотека која вам омогућава додавање аутентичност заснована на облаку на веб локацију. Коришћење саме библиотеке не захтева да користите њихове услуге.
cd client # installation using npm npm install @auth0/angular-jwt # installation using yarn yarn add @auth0/angular-jwt
Доћи ћемо до кода за секунду, али док смо већ код тога, подесимо и серверску страну. Користићемо body-parser
, jsonwebtoken
и express-jwt
библиотеке како би Ноде разумео ЈСОН ПОСТ тела и ЈВТ-ове.
cd server # installation using npm npm install body-parser jsonwebtoken express-jwt # installation using yarn yarn add body-parser jsonwebtoken express-jwt
Прво, потребан нам је начин за аутентификацију корисника пре него што им дамо токен. За наш једноставан демо, поставићемо само фиксну крајњу тачку за потврду идентитета са чврсто кодираним корисничким именом и лозинком. Ово може бити једноставно или сложено колико захтева ваша апликација. Важно је послати ЈВТ.
У server/app.js
додајте унос испод другог require
редови како следи:
const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const expressJwt = require('express-jwt');
Као и следеће:
app.use(bodyParser.json()); app.post('/api/auth', function(req, res) { const body = req.body; const user = USERS.find(user => user.username == body.username); if(!user || body.password != 'todo') return res.sendStatus(401); var token = jwt.sign({userID: user.id}, 'todo-app-super-shared-secret', {expiresIn: '2h'}); res.send({token}); });
Ово је углавном основни ЈаваСцрипт код. Добијамо ЈСОН тело које је прослеђено у /auth
крајњу тачку, пронађите корисника који се подудара с тим корисничким именом, проверите да ли се корисник и лозинка подударају и вратите 401 Unauthorized
ХТТП грешка ако није.
Важан део је генерација токена и то ћемо рашчланити по три параметра. Синтакса за sign
је следећи: jwt.sign(payload, secretOrPrivateKey, [options, callback])
, где:
payload
је литерарни објекат парова кључ / вредност који желите да кодирате у оквиру свог токена. Те информације тада може декодирати из токена свако ко има кључ за дешифровање. У нашем примеру кодирамо user.id
тако да када поново примимо токен на задњем крају ради потврде идентитета, знамо са којим корисником имамо посла.secretOrPrivateKey
је или дељени тајни кључ ХМАЦ шифровања - ово је оно што смо ради једноставности користили у нашој апликацији или приватни кључ РСА / ЕЦДСА енкрипције.options
представља низ опција које се могу проследити кодеру у облику парова кључ / вредност. Обично наводимо најмање expiresIn
(постаје exp
резервисана тужба) и issuer
(iss
резервисано полагање права) тако да токен не важи заувек, а сервер може да провери да ли је токен у ствари првобитно издао.callback
је функција коју треба позвати након завршетка кодирања, уколико неко жели асинхроно руковати кодирањем токена. (Такође можете читати о више детаља о options
и како се користи криптографија јавног кључа уместо заједничког тајног кључа .)
Направити Ангулар 6 да ради са нашим ЈВТ-ом прилично је једноставно користећи angular-jwt
. Једноставно додајте следеће у client/src/app/app.modules.ts
:
import { JwtModule } from '@auth0/angular-jwt'; // ... export function tokenGetter() { return localStorage.getItem('access_token'); } @NgModule({ // ... imports: [ BrowserModule, AppRoutingModule, HttpClientModule, FormsModule, // Add this import here JwtModule.forRoot({ config: { tokenGetter: tokenGetter, whitelistedDomains: ['localhost:4000'], blacklistedRoutes: ['localhost:4000/api/auth'] } }) ], // ... }
То је у основи све што је потребно. Наравно, морамо додати још кода за почетну аутентификацију, али angular-jwt
библиотека брине о слању токена уз сваки ХТТП захтев.
tokenGetter()
функција ради тачно оно што каже, али како ће се применити зависи само од вас. Одлучили смо да вратимо токен који смо сачували у localStorage
. Слободни сте да наведете било који други начин који желите, све док он враћа ЈСОН веб токен кодирани низ.whiteListedDomains
опција постоји, тако да можете ограничити на које домене се ЈВТ шаље, тако да јавни АПИ-ји неће примати и ваш ЈВТ.blackListedRoutes
опција вам омогућава да одредите одређене руте које не би требале да приме ЈВТ, чак и ако су на домену са беле листе. На пример, крајња тачка за потврду идентитета не треба да је прими јер нема смисла: токен је ионако нулан када се ионако позове.У овом тренутку имамо начин да генеришемо ЈВТ за датог корисника помоћу /auth
крајњу тачку на нашем АПИ-ју, а водовод смо обавили на Ангулар-у за слање ЈВТ-а са сваким ХТТП захтевом. Одлично, али могли бисте да нагласите да се апсолутно ништа није променило за корисника. И били бисте у праву. И даље можемо доћи до сваке странице у нашој апликацији и можемо позвати било коју крајњу тачку АПИ-ја, а да чак ни не пошаљемо ЈВТ. Није добро!
колико принципа дизајна постоји
Морамо да ажурирамо нашу клијентску апликацију да бисмо били забринути ко је пријављен, а такође и наш АПИ да захтева ЈВТ. Хајде да почнемо.
За пријављивање ће нам бити потребна нова компонента Ангулар. Ради краткоће, учинићу ово што једноставнијим. Такође ће нам требати услуга која ће се бавити свим нашим захтевима за потврду идентитета и Угаона гарда да бисмо заштитили руте којима не би требало да буду доступне пре пријављивања. Урадићемо следеће у контексту клијентске апликације.
cd client ng g component login --spec=false --inline-style ng g service auth --flat --spec=false ng g guard auth --flat --spec=false
Ово је требало генерисати четири нове датотеке у client
директоријум:
src/app/login/login.component.html src/app/login/login.component.ts src/app/auth.service.ts src/app/auth.guard.ts
Даље, морамо да пружимо услугу потврде идентитета и заштиту наше апликације. Ажурирање client/src/app/app.modules.ts
:
import { AuthService } from './auth.service'; import { AuthGuard } from './auth.guard'; // ... providers: [ TodoService, UserService, AuthService, AuthGuard ],
А затим ажурирајте рутирање у client/src/app/app-routing.modules.ts
да бисте користили заштитник за аутентификацију и обезбедили руту за компоненту за пријаву.
// ... import { LoginComponent } from './login/login.component'; import { AuthGuard } from './auth.guard'; const routes: Routes = [ { path: 'todos', component: TodoListComponent, canActivate: [AuthGuard] }, { path: 'users', component: UserListComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent}, // ...
На крају, ажурирајте client/src/app/auth.guard.ts
са следећим садржајима:
import { Injectable } from '@angular/core'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router) { } canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) { if (localStorage.getItem('access_token')) { return true; } this.router.navigate(['login']); return false; } }
За нашу демо апликацију једноставно проверавамо да ли постоји ЈВТ у локалном складишту. У стварним апликацијама декодирали бисте токен и проверили његову ваљаност, истек итд. На пример, могли бисте да користите ЈвтХелперСервице за ово.
У овом тренутку, наша апликација Ангулар сада ће вас увек преусмерити на страницу за пријављивање, јер ми не можемо да се пријавимо. Исправимо то, почевши од услуге потврде идентитета у client/src/app/auth.service.ts
:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class AuthService { constructor(private http: HttpClient) { } login(username: string, password: string): Observable { return this.http.post('/api/auth', {username: username, password: password}) .pipe( map(result => { localStorage.setItem('access_token', result.token); return true; }) ); } logout() { localStorage.removeItem('access_token'); } public get loggedIn(): boolean { return (localStorage.getItem('access_token') !== null); } }
Наша услуга потврде идентитета има само две функције, login
и logout
:
login
POST
с обезбеђеним username
и password
на наш задњи крај и поставља access_token
у localStorage
ако прими један назад. Ради једноставности, овде нема руковања грешкама. logout
једноставно брише access_token
од localStorage
, захтевајући да се набави нови токен пре него што се поново може приступити било чему другом.loggedIn
је логичко својство помоћу којег можемо брзо утврдити да ли је корисник пријављен или није.И на крају, компонента за пријаву. Они немају никакве везе са стварним радом са ЈВТ-ом, зато слободно копирајте и залепите у client/src/app/login/login.components.html
:
{{error}}
Username Password Login
И client/src/app/login/login.components.ts
требаће:
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; import { Router } from '@angular/router'; import { first } from 'rxjs/operators'; @Component({ selector: 'app-login', templateUrl: './login.component.html' }) export class LoginComponent { public username: string; public password: string; public error: string; constructor(private auth: AuthService, private router: Router) { } public submit() { this.auth.login(this.username, this.password) .pipe(first()) .subscribe( result => this.router.navigate(['todos']), err => this.error = 'Could not authenticate' ); } }
Ето, наш пример пријаве за Ангулар 6:
У овој фази требали бисмо бити у могућности да се пријавимо (користећи jemma
, paul
или sebastian
са лозинком todo
) и поново видите све екране. Али наша апликација показује иста заглавља за навигацију и нема начина да се одјавите без обзира на тренутно стање. Поправимо то пре него што пређемо на поправљање нашег АПИ-ја.
У client/src/app/app.component.ts
, замените целу датотеку следећим:
import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { AuthService } from './auth.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(private auth: AuthService, private router: Router) { } logout() { this.auth.logout(); this.router.navigate(['login']); } }
И за client/src/app/app.component.html
замените овај одељак следећим:
Todo List Users Login Logout
Уверили смо контекст наше навигације да би требало да приказује само одређене ставке у зависности од тога да ли је корисник пријављен или не. auth.loggedIn
може се, наравно, користити било где где можете да увезете услугу потврде идентитета.
Можда размишљате, ово је сјајно ... изгледа да све делује предивно . Али покушајте да се пријавите са сва три различита корисничка имена и приметићете нешто: Сви они враћају исту листу задатака. Ако погледамо наш АПИ сервер, можемо видети да сваки корисник у ствари има своју листу ставки, па шта има?
Па, запамтите када смо започели, кодирали смо наш /todos
Крајња тачка АПИ-ја да увек врати списак задатака за userID=1
. То је било зато што нисмо имали начина да сазнамо ко је тренутно пријављени корисник.
Сада то радимо, па да видимо како је лако осигурати своје крајње тачке и користити информације кодиране у ЈВТ-у за пружање потребног корисничког идентитета. У почетку додајте овај један ред у свој server/app.js
датотека тачно испод последњег app.use()
позив:
app.use(expressJwt({secret: 'todo-app-super-shared-secret'}).unless({path: ['/api/auth']}));
Користимо express-jwt
миддлеваре, реците му шта је дељена тајна и наведите низ путања за које не би требало да захтева ЈВТ. И то је то. Нема потребе да додирујете сваку крајњу тачку, направите if
изјаве свуда или било шта друго.
Интерни софтвер интервенира износи неколико претпоставки. На пример, претпоставља Authorization
ХТТП заглавље следи уобичајени ЈВТ образац од Bearer {token}
. (Библиотека, међутим, има пуно опција за прилагођавање њеног рада, ако то није случај. Погледајте екпресс-јвт Употреба За више детаља.)
Наш други циљ је да користимо информације кодиране ЈВТ-ом да бисмо сазнали ко упућује позив. Још једном express-jwt
долази у помоћ. Као део читања токена и његове верификације, он поставља кодирану корисну тежину коју смо послали у процесу потписивања на променљиву req.user
у Екпресс-у. Тада га можемо користити за тренутни приступ било којој променљивој коју смо сачували. У нашем случају постављамо userID
једнак идентификованом ИД-у корисника и као такав га можемо користити директно као req.user.userID
.
Ажурирање server/app.js
поново и промените /todos
крајња тачка да гласи како следи:
res.send(getTodos(req.user.userID));
И то је то. Наш АПИ је сада заштићен од неовлашћеног приступа и можемо сигурно утврдити ко је наш аутентификовани корисник у било којој крајњој тачки. Наша клијентска апликација такође има једноставан поступак потврде идентитета, а све ХТТП услуге које напишемо и које позивају нашу АПИ крајњу тачку аутоматски ће имати приложен токен за потврду идентитета.
дизајнери огласа користе кретање како би
Ако сте клонирали Гитхуб спремиште и једноставно желите да видите крајњи резултат на делу, код можете погледати у коначном облику користећи:
git checkout with-jwt
Надам се да вам је ово упутство драгоцено за додавање ЈВТ аутентификација у своје Ангулар апликације. Хвала за читање!
Повезан: Водич за ЈСОН веб токене: Пример у Ларавел-у и АнгуларЈС-уУ програмском смислу, токен има много дефиниција. Што се тиче безбедности и аутентификације, то је једноставно непрозирни низ који кодира малу количину информација које се лако могу пренети и сачувати, али са готово нула шанси за колизије са било којим другим токеном.
Аутентификација заснована на токенима једноставно значи кодирање података потребних за аутентификацију и ауторизацију корисника у токен, а затим коришћење тог необавезно криптографски потписаног токена за ауторизацију уместо комбинација корисничког имена / лозинке приликом приступа заштићеним ресурсима.
ЈВТ је скраћеница за ЈСОН Веб Токен, што у основи значи да је то ЈСОН објекат са заглављем, корисним оптерећењем и потписом. Представља сигуран начин размене информација о аутентификацији између две стране преко мреже када се користе заједно са другим технологијама попут ССЛ-а.
ОАутх 2.0 је стандардни протокол за извођење ауторизације на великом броју подржаних платформи. На пример, Гоогле, Фацебоок и ОпенИД користе ОАутх 2.0. Дефинише кораке и формат који треба следити за аутентификацију помоћу датог сервера за потврду идентитета и добијање приступа заштићеним ресурсима.