JSON Web Token Eğitimi: Laravel ve AngularJS'de Bir Örnek
Yayınlanan: 2022-03-11Tek sayfalı uygulamaların, mobil uygulamaların ve RESTful API hizmetlerinin artan popülaritesi ile web geliştiricilerinin arka uç kodu yazma şekli önemli ölçüde değişti. AngularJS ve BackboneJS gibi teknolojilerle artık biçimlendirme oluşturmak için fazla zaman harcamıyoruz, bunun yerine ön uç uygulamalarımızın tükettiği API'ler oluşturuyoruz. Arka ucumuz daha çok iş mantığı ve verilerle ilgiliyken, sunum mantığı yalnızca ön uç veya mobil uygulamalara taşınır. Bu değişiklikler, modern uygulamalarda kimlik doğrulamayı uygulamanın yeni yollarına yol açmıştır.
Kimlik doğrulama, herhangi bir web uygulamasının en önemli bölümlerinden biridir. Onlarca yıldır, tanımlama bilgileri ve sunucu tabanlı kimlik doğrulama en kolay çözümdü. Ancak, modern Mobil ve Tek Sayfa Uygulamalarında kimlik doğrulamanın ele alınması zor olabilir ve daha iyi bir yaklaşım gerektirebilir. API'ler için kimlik doğrulama sorunlarına yönelik en iyi bilinen çözümler, OAuth 2.0 ve JSON Web Simgesidir (JWT).
Bu JSON Web Token eğitimine girmeden önce, JWT tam olarak nedir?
JSON Web Simgesi nedir?
Dijital imza aracılığıyla doğrulanabilen ve güvenilen bilgileri göndermek için bir JSON Web Simgesi kullanılır. Özgünlüğünü doğrulamak için kriptografik olarak imzalanmış ve veri yükü hassas bilgiler içeriyorsa şifrelenebilen, kompakt ve URL güvenli bir JSON nesnesi içerir.
Kompakt yapısı nedeniyle JWT, genellikle HTTP Authorization
başlıklarında veya URL sorgu parametrelerinde kullanılır.
JSON Web Simgesinin Yapısı
Bir JWT, nokta karakterleriyle ayrılmış bir base64url kodlu değerler dizisi olarak temsil edilir.
İşte bir JWT jeton örneği:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0 . yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw
başlık
Başlık, belirteç için meta verileri içerir ve minimum düzeyde imza türünü ve şifreleme algoritmasını içerir. (JSON nesnesini güzelleştirmek için bir JSON biçimlendirici aracı kullanabilirsiniz.)
Örnek Başlık
{ "alg": "HS256", "typ": "JWT" }
Bu JWT örnek başlığı, kodlanmış nesnenin bir JSON Web Simgesi olduğunu ve HMAC SHA-256 algoritması kullanılarak imzalandığını bildirir.
Bu bir kez base64 ile kodlandığında, JWT'mizin ilk kısmına sahibiz.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Yük (Talepler)
JWT bağlamında, bir talep, bir varlık (tipik olarak kullanıcı) hakkında bir ifade ve ayrıca belirtecin kendisiyle ilgili ek meta veriler olarak tanımlanabilir. İddia, iletmek istediğimiz ve sunucunun JSON Web Token kimlik doğrulamasını düzgün bir şekilde işlemek için kullanabileceği bilgileri içerir. Sağlayabileceğimiz birden fazla talep var; bunlara kayıtlı talep adları, genel talep adları ve özel talep adları dahildir.
Kayıtlı JWT Talepleri
Bunlar, IANA JSON Web Belirteci Talepleri kayıt defterinde kayıtlı olan taleplerdir. Bu JWT taleplerinin zorunlu olması amaçlanmamıştır, bunun yerine bir dizi faydalı, birlikte çalışabilir talep için bir başlangıç noktası sağlamayı amaçlamaktadır.
Bunlar şunları içerir:
- iss : Belirteci veren kuruluş
- sub : Belirtecin konusu
- aud : Belirtecin hedef kitlesi
- exp : Unix zamanında tanımlanan JWT sona erme süresi
- nbf : JWT'nin işlenmek üzere kabul edilmemesi gereken süreyi tanımlayan "önce değil" zamanı
- iat : Belirtecin düzenlendiği Unix zamanında "verilme zamanı"
- jti : JWT kimliği talebi, JWT için benzersiz bir tanımlayıcı sağlar
Kamu Alacakları
Kamu hak taleplerinin çarpışmaya dayanıklı adlara sahip olması gerekir. Adı bir URI veya URN yaparak, gönderici ve alıcının kapalı bir ağın parçası olmadığı JWT'ler için adlandırma çakışmaları önlenir.
Genel hak talebi adına bir örnek şu olabilir: https://www.toptal.com/jwt_claims/is_admin
ve en iyi uygulama, belgeleme için başvurunun kaldırılabilmesi için talebi açıklayan bu konuma bir dosya yerleştirmektir.
Özel Talepler
Özel talep adları, JWT'lerin yalnızca kapalı bir ortamda, örneğin bir işletme içinde olduğu gibi, bilinen sistemler arasında değiş tokuş edildiği yerlerde kullanılabilir. Bunlar, kullanıcı kimlikleri, kullanıcı rolleri veya diğer bilgiler gibi kendimizi tanımlayabileceğimiz iddialardır.
Kapalı veya özel bir sistemin dışında, birbiriyle çelişen anlamsal anlamlara sahip olabilecek talep adlarının kullanılması çakışmaya tabidir, bu nedenle bunları dikkatli kullanın.
Bir web belirtecini mümkün olduğunca küçük tutmak istediğimizi unutmamak önemlidir, bu nedenle genel ve özel taleplerde yalnızca gerekli verileri kullanın.
JWT Örnek Yükü
{ "iss": "toptal.com", "exp": 1426420800, "https://www.toptal.com/jwt_claims/is_admin": true, "company": "Toptal", "awesome": true }
Bu örnek yükün iki kayıtlı talebi, bir genel talebi ve iki özel talebi vardır. Base64 ile kodlandığında, JWT'mizin ikinci kısmına sahibiz.
eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0
İmza
JWT standardı, son imzalı belirteci oluşturmak için JSON Web İmzası (JWS) belirtimini izler. Kodlanmış JWT Başlığı ve kodlanmış JWT Yükü birleştirilerek ve HMAC SHA-256 gibi güçlü bir şifreleme algoritması kullanılarak imzalanarak oluşturulur. İmzanın gizli anahtarı sunucu tarafından tutulur, böylece mevcut jetonları doğrulayabilir ve yenilerini imzalayabilir.
$encodedContent = base64UrlEncode(header) + "." + base64UrlEncode(payload); $signature = hashHmacSHA256($encodedContent);
Bu bize JWT'mizin son bölümünü verir.
yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw
JWT Güvenliği ve Şifreleme
Ortadaki adam saldırılarını önlemek için TLS/SSL'yi JWT ile birlikte kullanmak çok önemlidir. Çoğu durumda, hassas bilgiler içeriyorsa bu, JWT yükünü şifrelemek için yeterli olacaktır. Bununla birlikte, ek bir koruma katmanı eklemek istersek, JSON Web Encryption (JWE) belirtimini kullanarak JWT yükünün kendisini şifreleyebiliriz.
Elbette, JWE kullanmanın ek yükünden kaçınmak istiyorsak, başka bir seçenek de hassas bilgileri veritabanımızda tutmak ve hassas verilere erişmemiz gerektiğinde sunucuya ek API çağrıları için simgemizi kullanmaktır.
Web Belirteçlerine Neden İhtiyaç Duyulur?
JWT kimlik doğrulamasını kullanmanın tüm faydalarını görmeden önce, geçmişte kimlik doğrulamanın nasıl yapıldığına bakmalıyız.
Sunucu Tabanlı Kimlik Doğrulama
HTTP protokolü durumsuz olduğundan, kullanıcı bilgilerini depolamak için bir mekanizma ve oturum açtıktan sonra sonraki her istekte kullanıcının kimliğini doğrulamanın bir yolu olmalıdır. Çoğu web sitesi, kullanıcının oturum kimliğini saklamak için çerezleri kullanır.
Nasıl çalışır
Tarayıcı, sunucuya kullanıcının kimliğini ve parolasını içeren bir POST isteğinde bulunur. Sunucu, kullanıcının tarayıcısında ayarlanan ve kullanıcıyı tanımlamak için bir oturum kimliği içeren bir tanımlama bilgisi ile yanıt verir.
Kullanıcı verileri sunucuda depolandığından, sonraki her istekte sunucunun bu oturumu bulması ve seri durumdan çıkarması gerekir.
Sunucu Tabanlı Kimlik Doğrulamanın Dezavantajları
Ölçeklenmesi zor : Sunucunun bir kullanıcı için bir oturum oluşturması ve bunu sunucuda bir yerde sürdürmesi gerekir. Bu, bellekte veya bir veritabanında yapılabilir. Dağıtılmış bir sistemimiz varsa, uygulama sunucusuna bağlı olmayan ayrı bir oturum deposu kullandığımızdan emin olmalıyız.
Kaynaklar arası istek paylaşımı (CORS) : Başka bir etki alanından ("çapraz kaynak") bir kaynak getirmek için AJAX çağrılarını kullanırken yasak isteklerle ilgili sorunlarla karşılaşabiliriz, çünkü varsayılan olarak HTTP istekleri çapraz- köken istekleri.
Web çerçevesiyle eşleşme : Sunucu tabanlı kimlik doğrulamayı kullanırken, çerçevemizin kimlik doğrulama şemasına bağlıyız. Farklı programlama dillerinde yazılmış farklı web çerçeveleri arasında oturum verilerini paylaşmak gerçekten zor, hatta imkansız.
Jeton Tabanlı Kimlik Doğrulama
Belirteç tabanlı/JWT kimlik doğrulaması durumsuzdur, bu nedenle oturumda kullanıcı bilgilerini depolamaya gerek yoktur. Bu bize, kullanıcının nerede oturum açtığı konusunda endişelenmeden uygulamamızı ölçeklendirme yeteneği verir. Oturum açtığımız alandan farklı bir etki alanından güvenli bir kaynak almak için aynı belirteci kolayca kullanabiliriz.
JSON Web Belirteçleri Nasıl Çalışır?
Bir tarayıcı veya mobil istemci, kimlik doğrulama sunucusuna kullanıcı oturum açma bilgilerini içeren bir istekte bulunur. Kimlik doğrulama sunucusu, yeni bir JWT erişim belirteci oluşturur ve bunu istemciye geri gönderir. Kısıtlanmış bir kaynağa yapılan her istekte, istemci, sorgu dizesinde veya Authorization
başlığında erişim belirtecini gönderir. Sunucu daha sonra belirteci doğrular ve geçerliyse güvenli kaynağı istemciye döndürür.
Kimlik doğrulama sunucusu, herhangi bir güvenli imza yöntemini kullanarak belirteci imzalayabilir. Örneğin, gizli anahtarı tüm taraflar arasında paylaşmak için güvenli bir kanal varsa HMAC SHA-256 gibi simetrik bir anahtar algoritması kullanılabilir. Alternatif olarak, RSA gibi bir asimetrik, açık anahtar sistemi de kullanılabilir ve bu da daha fazla anahtar paylaşımı ihtiyacını ortadan kaldırır.
Belirteç Tabanlı Kimlik Doğrulamanın Avantajları
Vatansız, ölçeklenmesi daha kolay : Belirteç, kullanıcıyı tanımlamak için tüm bilgileri içerir ve oturum durumuna olan ihtiyacı ortadan kaldırır. Yük dengeleyici kullanırsak, kullanıcıyı oturum açtığımız aynı sunucuya bağlı kalmak yerine herhangi bir sunucuya geçirebiliriz.
Yeniden Kullanılabilirlik: Kullanıcının kimliğini doğrulamak için aynı belirteci yeniden kullanan, birden çok platform ve etki alanında çalışan birçok ayrı sunucumuz olabilir. İzinleri başka bir uygulamayla paylaşan bir uygulama oluşturmak kolaydır.
JWT Security : Çerez kullanmadığımız için siteler arası istek sahteciliği (CSRF) saldırılarına karşı korumamız gerekmiyor. İçerilerine herhangi bir hassas bilgi koymamız gerekiyorsa, jetonlarımızı yine de JWE kullanarak şifrelemeli ve ortadaki adam saldırılarını önlemek için jetonlarımızı HTTPS üzerinden iletmeliyiz.
Performans : Her istekte oturumu bulmak ve seri durumdan çıkarmak için sunucu tarafı araması yoktur. Tek yapmamız gereken, jetonu doğrulamak ve içeriğini ayrıştırmak için HMAC SHA-256'yı hesaplamak.
Laravel 5 ve AngularJS kullanan bir JSON Web Simgesi Örneği
Bu JWT eğitiminde, iki popüler web teknolojisinde JSON Web Belirteçlerini kullanarak temel kimlik doğrulamanın nasıl uygulanacağını göstereceğim: arka uç kodu için Laravel 5 ve ön uç Tek Sayfa Uygulaması (SPA) örneği için AngularJS. (Demonun tamamını burada ve kaynak kodunu bu GitHub deposunda bulabilirsiniz, böylece öğreticiyi takip edebilirsiniz.)
Bu JSON web belirteci örneği, taleplerde iletilen bilgilerin gizliliğini sağlamak için herhangi bir şifreleme kullanmayacaktır. Pratikte bu genellikle iyidir, çünkü TLS/SSL isteği şifreler. Ancak belirteç, kullanıcının sosyal güvenlik numarası gibi hassas bilgileri içerecekse, JWE kullanılarak da şifrelenmelidir.
Laravel Arka Uç Örneği
Kullanıcı kaydını işlemek, kullanıcı verilerini bir veritabanında kalıcı kılmak ve Angular uygulamasının kullanması için kimlik doğrulaması gerektiren bazı kısıtlı verileri sağlamak için Laravel'i kullanacağız. Kaynaklar arası kaynak paylaşımını (CORS) da simüle etmek için örnek bir API alt etki alanı oluşturacağız.
Kurulum ve Proje Önyükleme
Laravel'i kullanabilmek için makinemize Composer paket yöneticisini kurmamız gerekiyor. Laravel'de geliştirme yaparken, Vagrant'ın Laravel Homestead önceden paketlenmiş “kutusunu” kullanmanızı öneririm. İşletim sistemimizden bağımsız olarak bize eksiksiz bir geliştirme ortamı sağlar.
JWT Laravel uygulamamızı önyüklemenin en kolay yolu, bir Composer paketi Laravel Installer kullanmaktır.
composer global require "laravel/installer=~1.1"
Artık hepimiz laravel new jwt
new jwt'yi çalıştırarak yeni bir Laravel projesi oluşturmaya hazırız.
Bu süreçle ilgili herhangi bir sorunuz için lütfen resmi Laravel belgelerine bakın.
Temel Laravel 5 uygulamasını oluşturduktan sonra, yerel ortamımız için klasör eşlemelerini ve etki alanı yapılandırmasını yapılandıracak olan Homestead.yaml
dosyamızı kurmamız gerekiyor.
Homestead.yaml
dosyası örneği:
--- 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 kutumuzu vagrant up
komutu ile boot edip vagrant ssh
ile giriş yaptıktan sonra, daha önce tanımlanmış proje dizinine gidiyoruz. Yukarıdaki örnekte bu, /home/vagrant/coding/jwt
olacaktır. Artık veritabanımızda gerekli kullanıcı tablolarını oluşturmak için php artisan migrate
komutunu çalıştırabiliriz.
Besteci Bağımlılıklarını Yükleme
Neyse ki, Laravel üzerinde çalışan ve uygulamamızı yeniden kullanabileceğimiz ve genişletebileceğimiz birçok harika paketi sürdüren bir geliştiriciler topluluğu var. Bu örnekte, sunucu tarafında belirteçleri işlemek için Sean Tymon tarafından tymon tymon/jwt-auth
ve Barry vd tarafından barryvdh/laravel-cors
. Heuvel, CORS'u işlemek için.
jwt-auth
composer.json
tymon/jwt-auth
paketini gerekli kılın ve bağımlılıklarımızı güncelleyin.
composer require tymon/jwt-auth 0.5.*
JWTAuthServiceProvider
app/config/app.php
sağlayıcılar dizimize ekleyin.
'Tymon\JWTAuth\Providers\JWTAuthServiceProvider'
Ardından, app/config/app.php
dosyasında, aliases
dizisinin altına JWTAuth
cephesini ekliyoruz.
'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth'
Son olarak, aşağıdaki komutu kullanarak paket yapılandırmasını yayınlamak isteyeceğiz: php artisan config:publish tymon/jwt-auth
JSON Web belirteçleri, bir gizli anahtar kullanılarak şifrelenir. Bu anahtarı php artisan jwt:generate
komutunu kullanarak üretebiliriz. config/jwt.php
dosyamızın içine yerleştirilecektir. Ancak üretim ortamında, parolalarımızın veya API anahtarlarımızın yapılandırma dosyalarının içinde olmasını asla istemiyoruz. Bunun yerine, bunları sunucu ortam değişkenlerinin içine yerleştirmeli ve env
işleviyle yapılandırma dosyasında bunlara başvurmalıyız. Örneğin:
'secret' => env('JWT_SECRET')
Bu paket ve tüm yapılandırma ayarları hakkında daha fazla bilgiyi Github'da bulabiliriz.
laravel-cors
besteci.json'da barryvdh/ composer.json
barryvdh/laravel-cors
paketini gerektir ve bağımlılıklarımızı güncelle.
composer require barryvdh/laravel-cors 0.4.x@dev
CorsServiceProvider
app/config/app.php
sağlayıcılar dizimize ekleyin.
'Barryvdh\Cors\CorsServiceProvider'
Ardından ara yazılımı app/Http/Kernel.php
.
'Barryvdh\Cors\Middleware\HandleCors'
php artisan vendor:publish
yayımla komutunu kullanarak yapılandırmayı yerel bir config/cors.php
dosyasında yayınlayın.
Bir cors.php
dosya yapılandırması örneği:
return [ 'defaults' => [ 'supportsCredentials' => false, 'allowedOrigins' => [], 'allowedHeaders' => [], 'allowedMethods' => [], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => [], ], 'paths' => [ 'v1/*' => [ 'allowedOrigins' => ['*'], 'allowedHeaders' => ['*'], 'allowedMethods' => ['*'], 'maxAge' => 3600, ], ], ];
HTTP İsteklerini Yönlendirme ve İşleme

Kısa olması için, tüm kodumu Laravel yönlendirmesinden ve kontrolörlere istek atamasından sorumlu olan route.php dosyasının içine koyacağım. Genellikle tüm HTTP isteklerimizi işlemek için özel denetleyiciler oluşturur ve kodumuzu modüler ve temiz tutardık.
AngularJS SPA görünümümüzü kullanarak yükleyeceğiz
Route::get('/', function () { return view('spa'); });
Kullanıcı Kaydı
Bir kullanıcı adı ve şifre ile /signup
için POST
isteği yaptığımızda, yeni bir kullanıcı oluşturmaya ve veritabanına kaydetmeye çalışacağız. Kullanıcı oluşturulduktan sonra bir JWT oluşturulur ve JSON yanıtı yoluyla döndürülür.
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')); });
Kullanıcı Girişi
Bir kullanıcı adı ve parola ile /signin
açmak için bir POST
isteği yaptığımızda, kullanıcının var olduğunu doğrular ve JSON yanıtı aracılığıyla bir JWT döndürür.
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')); });
Aynı Etki Alanında Kısıtlanmış Bir Kaynak Getirme
Kullanıcı oturum açtıktan sonra kısıtlı kaynağı getirebiliriz. Kimliği doğrulanmış bir kullanıcıya ihtiyaç duyan bir kaynağı simüle eden /restricted
bir rota oluşturdum. Bunu yapmak için, istek Authorization
başlığının veya sorgu dizesinin, arka ucun doğrulaması için JWT'yi sağlaması gerekir.
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() ] ]); } ]);
Bu örnekte, jwt-auth
paketinde sağlanan jwt-auth
ara yazılımını 'before' => 'jwt-auth'
kullanarak kullanıyorum. Bu ara yazılım, isteği filtrelemek ve JWT belirtecini doğrulamak için kullanılır. Belirteç geçersizse, mevcut değilse veya süresi dolmuşsa, ara katman yazılımı yakalayabileceğimiz bir istisna atar.
Laravel 5'te app/Exceptions/Handler.php
dosyasını kullanarak istisnaları yakalayabiliriz. render
işlevini kullanarak, atılan istisnaya dayalı olarak HTTP yanıtları oluşturabiliriz.
public function render($request, Exception $e) { if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException) { return response(['Token is invalid'], 401); } if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException) { return response(['Token has expired'], 401); } return parent::render($request, $e); }
Kullanıcının kimliği doğrulanmışsa ve belirteç geçerliyse, kısıtlı verileri güvenli bir şekilde JSON aracılığıyla ön uca döndürebiliriz.
API Alt Etki Alanından Kısıtlanmış Kaynakları Alma
Bir sonraki JSON web belirteci örneğinde belirteç doğrulaması için farklı bir yaklaşım izleyeceğiz. jwt-auth
ara katman yazılımı kullanmak yerine, istisnaları manuel olarak ele alacağız. API sunucusu api.jwt.dev/v1/restricted
POST
isteği yaptığımızda, bir çapraz kaynak isteği yapıyoruz ve arka uçta CORS'u etkinleştirmemiz gerekiyor. Neyse ki, config/cors.php
dosyasında zaten yapılandırdık.
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 Ön Uç Örneği
Kullanıcı kimlik doğrulaması ve örnek veriler için Laravel arka uç kimlik doğrulama sunucusuna yapılan API çağrılarına ve ayrıca kökenler arası örnek veriler için API sunucusuna dayanan bir ön uç olarak AngularJS kullanıyoruz. Projemizin ana sayfasına gittiğimizde, arka uç, Angular uygulamasını önyükleyecek resources/views/spa.blade.php
görünümüne hizmet edecek.
Angular uygulamasının klasör yapısı şöyledir:
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
Angular Uygulamasını Önyükleme
spa.blade.php
, uygulamayı çalıştırmak için gereken temel bilgileri içerir. Stil için Twitter Bootstrap'ı ve Bootswatch'tan özel bir tema kullanacağız. Bir AJAX çağrısı yaparken biraz görsel geri bildirim almak için, XHR isteklerini engelleyen ve bir yükleme çubuğu oluşturan açısal yükleme çubuğu komut dosyasını kullanacağız. Başlık bölümünde, aşağıdaki stil sayfalarına sahibiz:
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <link rel="stylesheet" href="/css/bootstrap.superhero.min.css"> <link rel="stylesheet" href="/lib/loading-bar.css">
İşaretlememizin altbilgisi, kitaplıklara referansların yanı sıra Angular modüller, denetleyiciler ve hizmetler için özel komut dosyalarımızı içerir.
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular-route.min.js"></script> <script src="/lib/ngStorage.js"></script> <script src="/lib/loading-bar.js"></script> <script src="/scripts/app.js"></script> <script src="/scripts/controllers.js"></script> <script src="/scripts/services.js"></script> </body>
Belirteçleri tarayıcının yerel deposuna kaydetmek için AngularJS için ngStorage
kitaplığını kullanıyoruz, böylece her istekte Authorization
başlığı aracılığıyla gönderebiliyoruz.
Üretim ortamında, elbette, performansı artırmak için tüm komut dosyası dosyalarımızı ve stil sayfalarımızı küçültür ve birleştiririz.
Kullanıcının oturum açma durumuna bağlı olarak uygun bağlantıların görünürlüğünü değiştirecek Bootstrap kullanarak bir gezinme çubuğu oluşturdum. Oturum açma durumu, denetleyicinin kapsamındaki bir token
değişkeninin varlığı ile belirlenir.
<div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">JWT Angular example</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li data-ng-show="token"><a ng-href="#/restricted">Restricted area</a></li> <li data-ng-hide="token"><a ng-href="#/signin">Sign in</a></li> <li data-ng-hide="token"><a ng-href="#/signup">Sign up</a></li> <li data-ng-show="token"><a ng-click="logout()">Logout</a></li> </ul> </div>
yönlendirme
Tüm ön uç rotalarımızı yapılandırmaktan sorumlu olan app.js
adında bir dosyamız var.
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: '/' });
Burada HomeController
veya RestrictedController
tarafından işlenen dört rota tanımladığımızı görebiliriz. Her rota, kısmi bir HTML görünümüne karşılık gelir. Ayrıca arka uca HTTP isteklerimiz için URL'leri içeren iki sabit tanımladık.
Engelleyici Talep Et
AngularJS'nin $http hizmeti, arka uçla iletişim kurmamıza ve HTTP istekleri yapmamıza olanak tanır. Bizim durumumuzda, her HTTP isteğini durdurmak ve kullanıcının kimliği doğrulanmışsa, JWT'mizi içeren bir Authorization
başlığı ile enjekte etmek istiyoruz. Global bir HTTP hata işleyicisi oluşturmak için bir önleyici de kullanabiliriz. Tarayıcının yerel deposunda mevcutsa bir belirteç enjekte eden önleyicimize bir örnek.
$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); } }; }]);
Kontrolörler
controllers.js
dosyasında uygulamamız için iki controller tanımladık: HomeController
ve RestrictedController
. HomeController
, oturum açma, kaydolma ve oturum kapatma işlevlerini yerine getirir. Oturum açma ve kayıt formlarından kullanıcı adı ve şifre verilerini, arka uca HTTP istekleri gönderen Auth
hizmetine iletir. Ardından belirteci yerel depolamaya kaydeder veya arka uçtan gelen yanıta bağlı olarak bir hata mesajı gösterir.
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
aynı şekilde davranır, yalnızca Data
hizmetindeki getRestrictedData
ve getApiData
işlevlerini kullanarak verileri getirir.
.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.'; }); }]);
Arka uç, yalnızca kullanıcının kimliği doğrulanmışsa kısıtlı verileri sunmaktan sorumludur. Bu, kısıtlanmış verilerle yanıt verebilmek için, bu verilere yönelik isteğin, Authorization
başlığı veya sorgu dizesi içinde geçerli bir JWT içermesi gerektiği anlamına gelir. Durum böyle değilse, sunucu bir 401 Yetkisiz hata durum koduyla yanıt verecektir.
Yetkilendirme Hizmeti
Auth hizmeti, oturum açmaktan ve arka uca HTTP isteklerini kaydetmekten sorumludur. İstek başarılı olursa yanıt, imzalı belirteci içerir, bu daha sonra base64'ün kodu çözülür ve ekteki belirteç talep bilgileri bir tokenClaims
değişkenine kaydedilir. Bu, getTokenClaims
işlevi aracılığıyla denetleyiciye iletilir.
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; } }; } ]);
Bilgi Servisi
Bu, bazı yapay kısıtlı veriler için API sunucusunun yanı sıra kimlik doğrulama sunucusuna istekte bulunan basit bir hizmettir. İsteği yapar ve başarı ve hata geri aramalarını denetleyiciye devreder.
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) } }; } ]);
Bu JSON Web Simgesi Eğitiminin Ötesinde
Belirteç tabanlı kimlik doğrulama, belirli bir kimlik doğrulama şemasına bağlı olmayan ayrıştırılmış sistemler oluşturmamızı sağlar. Belirteç herhangi bir yerde üretilebilir ve belirteci imzalamak için aynı gizli anahtarı kullanan herhangi bir sistemde tüketilebilir. Mobil kullanıma hazırdırlar ve çerez kullanmamızı gerektirmezler.
JSON Web Belirteçleri tüm popüler programlama dillerinde çalışır ve hızla popülerlik kazanmaktadır. Google, Microsoft ve Zendesk gibi şirketler tarafından destekleniyorlar. İnternet Mühendisliği Görev Gücü (IETF) tarafından standart özellikleri hala taslak sürümdedir ve gelecekte biraz değişebilir.
Güvenlik ayrıntılarının nasıl ele alınacağı ve sona erdiğinde belirteçlerin yenilenmesi gibi JWT'ler hakkında ele alınacak çok şey var, ancak JSON Web Simgesi öğreticisi, JWT'leri kullanmanın temel kullanımını ve daha da önemlisi avantajlarını göstermelidir.
Toptal Mühendislik Blogunda Daha Fazla Okuma:
- Node.js/TypeScript REST API Oluşturma, Bölüm 3: MongoDB, Kimlik Doğrulama ve Otomatik Testler