Firebase Kimlik Doğrulaması ile Rol Tabanlı API Nasıl Oluşturulur
Yayınlanan: 2022-03-11Bu eğiticide, kullanıcıları ve rolleri Firebase ve Node.js kullanarak yönetmek için bir REST API oluşturacağız. Ek olarak, hangi kullanıcıların belirli kaynaklara erişebileceğini yetkilendirmek (veya vermemek) için API'nin nasıl kullanılacağını göreceğiz.
Tanıtım
Hemen hemen her uygulama bir miktar yetkilendirme sistemi gerektirir. Bazı durumlarda, Kullanıcılar tablomuzla ayarlanan bir kullanıcı adı/parolayı doğrulamak yeterlidir, ancak çoğu zaman, belirli kullanıcıların belirli kaynaklara erişmesine izin vermek ve bunları diğerlerinden kısıtlamak için daha ayrıntılı bir izin modeline ihtiyacımız vardır. İkincisini desteklemek için bir sistem kurmak önemsiz değildir ve çok zaman alabilir. Bu eğiticide, hızlı bir şekilde çalışmaya başlamamıza yardımcı olacak, Firebase kullanarak rol tabanlı bir yetkilendirme API'sinin nasıl oluşturulacağını öğreneceğiz.
Rol Tabanlı Yetkilendirme
Bu yetkilendirme modelinde, belirli kullanıcılar yerine rollere erişim verilir ve bir kullanıcı, izin modelinizi nasıl tasarladığınıza bağlı olarak bir veya daha fazlasına sahip olabilir. Kaynaklar ise, bir kullanıcının onu yürütmesine izin vermek için belirli roller gerektirir.
Firebase
Firebase Kimlik Doğrulaması
Özetle, Firebase Authentication, genişletilebilir bir belirteç tabanlı kimlik doğrulama sistemidir ve diğerlerinin yanı sıra Google, Facebook ve Twitter gibi en yaygın sağlayıcılarla kullanıma hazır entegrasyonlar sağlar.
Esnek bir rol tabanlı API oluşturmak için yararlanacağımız özel talepleri kullanmamıza olanak tanır.
Taleplere herhangi bir JSON değeri koyabiliriz (örneğin, { role: 'admin' }
veya { role: 'manager' }
).
Ayarlandıktan sonra, özel talepler Firebase'in oluşturduğu jetona dahil edilecek ve erişimi kontrol etmek için değeri okuyabileceğiz.
Ayrıca, çoğu durumda fazlasıyla yeterli olacak çok cömert bir ücretsiz kota ile birlikte gelir.
Firebase İşlevleri
İşlevler, tam olarak yönetilen sunucusuz bir platform hizmetidir. Sadece kodumuzu Node.js'ye yazıp dağıtmamız gerekiyor. Firebase, altyapıyı isteğe bağlı olarak ölçeklendirme, sunucu yapılandırması ve daha fazlasıyla ilgilenir. Bizim durumumuzda, API'mizi oluşturmak ve HTTP aracılığıyla web'e maruz bırakmak için kullanacağız.
express.js
, express.js uygulamalarını farklı yollar için işleyiciler olarak ayarlamamıza olanak tanır; örneğin, bir Express uygulaması oluşturabilir ve onu /mypath
ve bu rotaya gelen tüm istekler, yapılandırılan app
tarafından işlenir.
Bir işlev bağlamında, Yönetici SDK'sını kullanarak tüm Firebase Kimlik Doğrulama API'sine erişebilirsiniz.
Kullanıcı API'sini bu şekilde oluşturacağız.
Ne İnşa Edeceğiz
Bu yüzden başlamadan önce, ne inşa edeceğimize bir göz atalım. Aşağıdaki uç noktalara sahip bir REST API oluşturacağız:
Http Fiil | Yol | Tanım | yetki |
---|---|---|---|
ELDE ETMEK | /kullanıcılar | Tüm kullanıcıları listeler | Yalnızca yöneticiler ve yöneticiler erişebilir |
İLETİ | /kullanıcılar | Yeni kullanıcı oluşturur | Yalnızca yöneticiler ve yöneticiler erişebilir |
ELDE ETMEK | /kullanıcılar/:id | :id kullanıcısını alır | Yöneticiler, yöneticiler ve :id ile aynı kullanıcının erişimi vardır |
YAMA | /kullanıcılar/:id | :id kullanıcısını günceller | Yöneticiler, yöneticiler ve :id ile aynı kullanıcının erişimi vardır |
SİLMEK | /kullanıcılar/:id | :id kullanıcısını siler | Yöneticiler, yöneticiler ve :id ile aynı kullanıcının erişimi vardır |
Bu uç noktaların her biri kimlik doğrulamasını yapacak, yetkilendirmeyi doğrulayacak, ilgili işlemi gerçekleştirecek ve son olarak anlamlı bir HTTP kodu döndürecektir.
Belirteci doğrulamak için gereken kimlik doğrulama ve yetkilendirme işlevlerini oluşturacağız ve taleplerin işlemi yürütmek için gerekli rolü içerip içermediğini kontrol edeceğiz.
API'yi Oluşturma
API'yi oluşturmak için şunlara ihtiyacımız olacak:
- Bir Firebase projesi
-
firebase-tools
yüklü
İlk olarak, Firebase'e giriş yapın:
firebase login
Ardından, bir İşlevler projesini başlatın:
firebase init ? Which Firebase CLI features do you want to set up for this folder? ... (O) Functions: Configure and deploy Cloud Functions ? Select a default Firebase project for this directory: {your-project} ? What language would you like to use to write Cloud Functions? TypeScript ? Do you want to use TSLint to catch probable bugs and enforce style? Yes ? Do you want to install dependencies with npm now? Yes
Bu noktada, Firebase Functions oluşturmak için minimum kurulumla bir Functions klasörünüz olacak.
src/index.ts
adresinde, İşlevlerinizin çalıştığını doğrulamak için yorumunu kaldırabileceğiniz bir helloWorld
örneği vardır. Daha sonra cd functions
yapabilir ve npm run serve
. Bu komut kodu aktaracak ve yerel sunucuyu başlatacaktır.
Sonuçları http://localhost:5000/{your-project}/us-central1/helloWorld adresinden kontrol edebilirsiniz.
İşlevin, 'index.ts: 'helloWorld'
adresinde adı olarak tanımlanan yolda gösterildiğine dikkat edin.
Firebase HTTP İşlevi Oluşturma
Şimdi API'mizi kodlayalım. Bir http Firebase işlevi oluşturacağız ve onu /api
yoluna bağlayacağız.
İlk önce, npm install express
.
src/index.ts
şunları yapacağız:
- firebase-admin SDK modülünü
admin.initializeApp();
-
api
https uç noktamızın işleyicisi olarak bir Express uygulamasını ayarlayın
import * as functions from 'firebase-functions'; import * as admin from 'firebase-admin'; import * as express from 'express'; admin.initializeApp(); const app = express(); export const api = functions.https.onRequest(app);
Şimdi, /api
giden tüm istekler app
örneği tarafından işlenecek.
Yapacağımız sonraki şey, app
örneğini CORS'u destekleyecek ve JSON gövde ayrıştırıcı ara yazılımı eklemek için yapılandırmaktır. Bu şekilde herhangi bir URL'den istekte bulunabilir ve JSON formatlı istekleri ayrıştırabiliriz.
Önce gerekli bağımlılıkları kuracağız.
npm install --save cors body-parser
npm install --save-dev @types/cors
Ve daha sonra:
//... import * as cors from 'cors'; import * as bodyParser from 'body-parser'; //... const app = express(); app.use(bodyParser.json()); app.use(cors({ origin: true })); export const api = functions.https.onRequest(app);
Son olarak, app
işleyeceği rotaları yapılandıracağız.
//... import { routesConfig } from './users/routes-config'; //… app.use(cors({ origin: true })); routesConfig(app) export const api = functions.https.onRequest(app);
Firebase Functions, işleyici olarak bir Express uygulamasını ve functions.https.onRequest(app);
—bu durumda, api
— app
tarafından da işlenecektir. Bu, api/users
gibi belirli uç noktalar yazmamıza ve daha sonra yapacağımız her HTTP fiili için bir işleyici belirlememize olanak tanır.
src/users/routes-config.ts
dosyasını oluşturalım
Burada, POST '/users'
bir create
işleyicisi ayarlayacağız.
import { Application } from "express"; import { create} from "./controller"; export function routesConfig(app: Application) { app.post('/users', create ); }
Şimdi src/users/controller.ts
dosyasını oluşturacağız.
Bu fonksiyonda önce tüm alanların gövde isteğinde olduğunu doğrularız ve ardından kullanıcıyı oluşturup özel talepleri ayarlıyoruz.
setCustomUserClaims'de { role }
öğesini geçiyoruz — diğer alanlar zaten setCustomUserClaims
tarafından ayarlanmıştır.
Herhangi bir hata oluşmazsa, oluşturulan kullanıcının kullanıcı uid
ile bir 201 kodu döndürürüz.
import { Request, Response } from "express"; import * as admin from 'firebase-admin' export async function create(req: Request, res: Response) { try { const { displayName, password, email, role } = req.body if (!displayName || !password || !email || !role) { return res.status(400).send({ message: 'Missing fields' }) } const { uid } = await admin.auth().createUser({ displayName, password, email }) await admin.auth().setCustomUserClaims(uid, { role }) return res.status(201).send({ uid }) } catch (err) { return handleError(res, err) } } function handleError(res: Response, err: any) { return res.status(500).send({ message: `${err.code} - ${err.message}` }); }
Şimdi, yetkilendirme ekleyerek işleyicinin güvenliğini sağlayalım. Bunu yapmak için, create
uç noktamıza birkaç işleyici ekleyeceğiz. express.js
ile sırayla yürütülecek bir işleyici zinciri ayarlayabilirsiniz. Bir işleyici içinde, kodu yürütebilir ve onu next()
işleyicisine iletebilir veya bir yanıt döndürebilirsiniz. Yapacağımız şey, önce kullanıcının kimliğini doğrulamak ve ardından çalıştırmaya yetkili olup olmadığını doğrulamaktır.
src/users/routes-config.ts
dosyasında:
//... import { isAuthenticated } from "../auth/authenticated"; import { isAuthorized } from "../auth/authorized"; export function routesConfig(app: Application) { app.post('/users', isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'] }), create ); }
src/auth/authenticated.ts
dosyalarını oluşturalım.
Bu işlevde, istek başlığında authorization
sahibi belirtecinin varlığını doğrulayacağız. Ardından, admin.auth().verifyidToken()
ile kodunu çözeceğiz ve daha sonra yetkilendirmeyi doğrulamak için kullanacağımız res.locals
değişkeninde kullanıcının uid
, role
ve email
kalıcı hale getireceğiz.
Belirtecin geçersiz olması durumunda, müşteriye bir 401 yanıtı göndeririz:
import { Request, Response } from "express"; import * as admin from 'firebase-admin' export async function isAuthenticated(req: Request, res: Response, next: Function) { const { authorization } = req.headers if (!authorization) return res.status(401).send({ message: 'Unauthorized' }); if (!authorization.startsWith('Bearer')) return res.status(401).send({ message: 'Unauthorized' }); const split = authorization.split('Bearer ') if (split.length !== 2) return res.status(401).send({ message: 'Unauthorized' }); const token = split[1] try { const decodedToken: admin.auth.DecodedIdToken = await admin.auth().verifyIdToken(token); console.log("decodedToken", JSON.stringify(decodedToken)) res.locals = { ...res.locals, uid: decodedToken.uid, role: decodedToken.role, email: decodedToken.email } return next(); } catch (err) { console.error(`${err.code} - ${err.message}`) return res.status(401).send({ message: 'Unauthorized' }); } }
Şimdi bir src/auth/authorized.ts
dosyası oluşturalım.
Bu işleyicide, kullanıcının bilgilerini daha önce belirlediğimiz res.locals
ve işlemi yürütmek için gerekli role sahip olup olmadığını doğrularız veya işlemin aynı kullanıcının yürütmesine izin vermesi durumunda, istek parametrelerindeki kimliği doğrularız. auth belirtecindeki ile aynıdır. Kullanıcı gerekli role sahip değilse, bir 403 döndürürüz.
import { Request, Response } from "express"; export function isAuthorized(opts: { hasRole: Array<'admin' | 'manager' | 'user'>, allowSameUser?: boolean }) { return (req: Request, res: Response, next: Function) => { const { role, email, uid } = res.locals const { id } = req.params if (opts.allowSameUser && id && uid === id) return next(); if (!role) return res.status(403).send(); if (opts.hasRole.includes(role)) return next(); return res.status(403).send(); } }
Bu iki yöntemle, gelen belirteçteki role
verilen isteklerin kimliğini doğrulayabileceğiz ve bunları yetkilendirebileceğiz. Bu harika, ancak Firebase proje konsolundan özel talepler belirlememize izin vermediğinden, bu uç noktalardan hiçbirini yürütemeyeceğiz. Bunu atlamak için Firebase Authentication Console'dan bir kök kullanıcı oluşturabiliriz.
Ve kodda bir e-posta karşılaştırması ayarlayın. Artık bu kullanıcıdan gelen istekleri tetiklerken tüm işlemleri gerçekleştirebileceğiz.
//... const { role, email, uid } = res.locals const { id } = req.params if (email === '[email protected]') return next(); //...
Şimdi kalan CRUD işlemlerini src/users/routes-config.ts
.
:id
parametresinin gönderildiği tek bir kullanıcıyı alma veya güncelleme işlemleri için aynı kullanıcının işlemi yürütmesine de izin veriyoruz.
export function routesConfig(app: Application) { //.. // lists all users app.get('/users', [ isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'] }), all ]); // get :id user app.get('/users/:id', [ isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'], allowSameUser: true }), get ]); // updates :id user app.patch('/users/:id', [ isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'], allowSameUser: true }), patch ]); // deletes :id user app.delete('/users/:id', [ isAuthenticated, isAuthorized({ hasRole: ['admin', 'manager'] }), remove ]); }
Ve src/users/controller.ts
üzerinde. Bu işlemlerde, Firebase Authentication ile etkileşim kurmak ve ilgili işlemleri gerçekleştirmek için yönetici SDK'sından yararlanırız. Daha önce create
işleminde yaptığımız gibi, her işlemde anlamlı bir HTTP kodu döndürürüz.
Güncelleme işlemi için, mevcut tüm alanları doğrularız ve istekte gönderilenler ile customClaims
geçersiz kılarız:
//.. export async function all(req: Request, res: Response) { try { const listUsers = await admin.auth().listUsers() const users = listUsers.users.map(mapUser) return res.status(200).send({ users }) } catch (err) { return handleError(res, err) } } function mapUser(user: admin.auth.UserRecord) { const customClaims = (user.customClaims || { role: '' }) as { role?: string } const role = customClaims.role ? customClaims.role : '' return { uid: user.uid, email: user.email || '', displayName: user.displayName || '', role, lastSignInTime: user.metadata.lastSignInTime, creationTime: user.metadata.creationTime } } export async function get(req: Request, res: Response) { try { const { id } = req.params const user = await admin.auth().getUser(id) return res.status(200).send({ user: mapUser(user) }) } catch (err) { return handleError(res, err) } } export async function patch(req: Request, res: Response) { try { const { id } = req.params const { displayName, password, email, role } = req.body if (!id || !displayName || !password || !email || !role) { return res.status(400).send({ message: 'Missing fields' }) } await admin.auth().updateUser(id, { displayName, password, email }) await admin.auth().setCustomUserClaims(id, { role }) const user = await admin.auth().getUser(id) return res.status(204).send({ user: mapUser(user) }) } catch (err) { return handleError(res, err) } } export async function remove(req: Request, res: Response) { try { const { id } = req.params await admin.auth().deleteUser(id) return res.status(204).send({}) } catch (err) { return handleError(res, err) } } //...
Artık fonksiyonu yerel olarak çalıştırabiliriz. Bunu yapmak için önce yerel olarak auth API'sine bağlanabilmek için hesap anahtarını ayarlamanız gerekir. O zaman koş:

npm run serve
API'yi dağıtın
Harika! Rol tabanlı API'mizi yazdığımıza göre, onu web'e dağıtabilir ve kullanmaya başlayabiliriz. Firebase ile dağıtım yapmak çok kolay, sadece firebase deploy
çalıştırmamız gerekiyor. Dağıtım tamamlandığında, yayınlanan URL'den API'mize erişebiliriz.
API URL'sini https://console.firebase.google.com/u/0/project/{your-project}/functions/list adresinde kontrol edebilirsiniz.
Benim durumumda, [https://us-central1-joaq-lab.cloudfunctions.net/api].
API'yi tüketmek
API'miz dağıtıldıktan sonra, onu kullanmanın birkaç yolu var - bu eğitimde, onu Postman aracılığıyla veya bir Angular uygulamasından nasıl kullanacağımı ele alacağım.
Herhangi bir tarayıcıda Tüm Kullanıcıları Listele URL'sini ( /api/users
) girersek, aşağıdakileri alırız:
Bunun nedeni, bir tarayıcıdan istek gönderirken, auth başlıkları olmadan bir GET isteği gerçekleştiriyor olmamızdır. Bu, API'mizin gerçekten beklendiği gibi çalıştığı anlamına gelir!
API'miz belirteçler aracılığıyla güvence altına alınmıştır; böyle bir belirteç oluşturmak için Firebase'in İstemci SDK'sını aramamız ve geçerli bir kullanıcı/parola kimlik bilgisi ile oturum açmamız gerekir. Başarılı olduğunda, Firebase yanıtta bir jeton gönderecek ve daha sonra gerçekleştirmek istediğimiz herhangi bir sonraki isteğin başlığına ekleyebiliriz.
Bir Açısal Uygulamadan
Bu eğitimde, bir Angular uygulamasından API'yi tüketmek için önemli parçaları gözden geçireceğim. Deponun tamamına buradan erişilebilir ve bir Angular uygulamasının nasıl oluşturulacağı ve @angular/fire kullanımı için nasıl yapılandırılacağı konusunda adım adım bir eğitime ihtiyacınız varsa, bu gönderiye göz atabilirsiniz.
Bu nedenle, oturum açmaya geri dönersek, kullanıcının bir kullanıcı adı ve parola girmesine izin vermek için <form>
içeren bir SignInComponent
sahip olacağız.
//... <form [formGroup]="form"> <div class="form-group"> <label>Email address</label> <input type="email" formControlName="email" class="form-control" placeholder="Enter email"> </div> <div class="form-group"> <label>Password</label> <input type="password" formControlName="password" class="form-control" placeholder="Password"> </div> </form> //...
Ve sınıfta signInWithEmailAndPassword
hizmetini kullanarakInWithEmailAndPassword ile AngularFireAuth
.
//... form: FormGroup = new FormGroup({ email: new FormControl(''), password: new FormControl('') }) constructor( private afAuth: AngularFireAuth ) { } async signIn() { try { const { email, password } = this.form.value await this.afAuth.auth.signInWithEmailAndPassword(email, password) } catch (err) { console.log(err) } } //..
Bu noktada Firebase projemize giriş yapabiliriz.
DevTools'da ağ isteklerini incelediğimizde, Firebase'in kullanıcı ve şifremizi doğruladıktan sonra bir jeton döndürdüğünü görebiliriz.
Bu belirteç, başlığımızın isteğini oluşturduğumuz API'ye göndermek için kullanacağımız simgedir. Belirteci tüm isteklere eklemenin bir yolu, bir HttpInterceptor
kullanmaktır.
Bu dosya, belirtecin AngularFireAuth
nasıl alınacağını ve başlığın isteğine nasıl ekleneceğini gösterir. Daha sonra interceptor dosyasını AppModule'de sağlarız.
http-interceptors/auth-token.interceptor.ts
@Injectable({ providedIn: 'root' }) export class AuthTokenHttpInterceptor implements HttpInterceptor { constructor( private auth: AngularFireAuth ) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return this.auth.idToken.pipe( take(1), switchMap(idToken => { let clone = req.clone() if (idToken) { clone = clone.clone({ headers: req.headers.set('Authorization', 'Bearer ' + idToken) }); } return next.handle(clone) }) ) } } export const AuthTokenHttpInterceptorProvider = { provide: HTTP_INTERCEPTORS, useClass: AuthTokenHttpInterceptor, multi: true }
app.module.ts
@NgModule({ //.. providers: [ AuthTokenHttpInterceptorProvider ] //... }) export class AppModule { }
Engelleyici ayarlandıktan sonra httpClient
isteklerde bulunabiliriz. Örneğin, burada tüm kullanıcıları listelediğimiz, kullanıcıyı kimliğine göre aldığımız, bir kullanıcı oluşturduğumuz ve bir kullanıcıyı güncellediğimiz bir UsersService
var.
//… export type CreateUserRequest = { displayName: string, password: string, email: string, role: string } export type UpdateUserRequest = { uid: string } & CreateUserRequest @Injectable({ providedIn: 'root' }) export class UserService { private baseUrl = '{your-functions-url}/api/users' constructor( private http: HttpClient ) { } get users$(): Observable<User[]> { return this.http.get<{ users: User[] }>(`${this.baseUrl}`).pipe( map(result => { return result.users }) ) } user$(id: string): Observable<User> { return this.http.get<{ user: User }>(`${this.baseUrl}/${id}`).pipe( map(result => { return result.user }) ) } create(user: CreateUserRequest) { return this.http.post(`${this.baseUrl}`, user) } edit(user: UpdateUserRequest) { return this.http.patch(`${this.baseUrl}/${user.uid}`, user) } }
Şimdi, oturum açmış kullanıcıyı kimliğine göre almak için API'yi çağırabilir ve aşağıdaki gibi bir bileşendeki tüm kullanıcıları listeleyebiliriz:
//... <div *ngIf="user$ | async; let user" class="col-12"> <div class="d-flex justify-content-between my-3"> <h4> Me </h4> </div> <ul class="list-group"> <li class="list-group-item d-flex justify-content-between align-items-center"> <div> <h5 class="mb-1">{{user.displayName}}</h5> <small>{{user.email}}</small> </div> <span class="badge badge-primary badge-pill">{{user.role?.toUpperCase()}}</span> </li> </ul> </div> <div class="col-12"> <div class="d-flex justify-content-between my-3"> <h4> All Users </h4> </div> <ul *ngIf="users$ | async; let users" class="list-group"> <li *ngFor="let user of users" class="list-group-item d-flex justify-content-between align-items-center"> <div> <h5 class="mb-1">{{user.displayName}}</h5> <small class="d-block">{{user.email}}</small> <small class="d-block">{{user.uid}}</small> </div> <span class="badge badge-primary badge-pill">{{user.role?.toUpperCase()}}</span> </li> </ul> //...
//... users$: Observable<User[]> user$: Observable<User> constructor( private userService: UserService, private userForm: UserFormService, private modal: NgbModal, private afAuth: AngularFireAuth ) { } ngOnInit() { this.users$ = this.userService.users$ this.user$ = this.afAuth.user.pipe( filter(user => !!user), switchMap(user => this.userService.user$(user.uid)) ) } //...
Ve işte sonuç.
role=user
olan bir kullanıcıyla oturum açarsak, yalnızca Ben bölümünün oluşturulacağına dikkat edin.
Ve ağ denetçisinden bir 403 alacağız. Bunun nedeni, API'de daha önce belirlediğimiz kısıtlamanın yalnızca "Yöneticilerin" tüm kullanıcıları listelemesine izin vermesidir.
Şimdi “kullanıcı oluştur” ve “kullanıcı düzenle” fonksiyonlarını ekleyelim. Bunu yapmak için önce bir UserFormComponent
ve bir UserFormService
oluşturalım.
<ng-container *ngIf="user$ | async"></ng-container> <div class="modal-header"> <h4 class="modal-title">{{ title$ | async}}</h4> <button type="button" class="close" (click)="dismiss()"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <form [formGroup]="form" (ngSubmit)="save()"> <div class="form-group"> <label>Email address</label> <input type="email" formControlName="email" class="form-control" placeholder="Enter email"> </div> <div class="form-group"> <label>Password</label> <input type="password" formControlName="password" class="form-control" placeholder="Password"> </div> <div class="form-group"> <label>Display Name</label> <input type="string" formControlName="displayName" class="form-control" placeholder="Enter display name"> </div> <div class="form-group"> <label>Role</label> <select class="custom-select" formControlName="role"> <option value="admin">Admin</option> <option value="manager">Manager</option> <option value="user">User</option> </select> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-outline-danger" (click)="dismiss()">Cancel</button> <button type="button" class="btn btn-primary" (click)="save()">Save</button> </div>
@Component({ selector: 'app-user-form', templateUrl: './user-form.component.html', styleUrls: ['./user-form.component.scss'] }) export class UserFormComponent implements OnInit { form = new FormGroup({ uid: new FormControl(''), email: new FormControl(''), displayName: new FormControl(''), password: new FormControl(''), role: new FormControl(''), }); title$: Observable<string>; user$: Observable<{}>; constructor( public modal: NgbActiveModal, private userService: UserService, private userForm: UserFormService ) { } ngOnInit() { this.title$ = this.userForm.title$; this.user$ = this.userForm.user$.pipe( tap(user => { if (user) { this.form.patchValue(user); } else { this.form.reset({}); } }) ); } dismiss() { this.modal.dismiss('modal dismissed'); } save() { const { displayName, email, role, password, uid } = this.form.value; this.modal.close({ displayName, email, role, password, uid }); } }
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class UserFormService { _BS = new BehaviorSubject({ title: '', user: {} }); constructor() { } edit(user) { this._BS.next({ title: 'Edit User', user }); } create() { this._BS.next({ title: 'Create User', user: null }); } get title$() { return this._BS.asObservable().pipe( map(uf => uf.title) ); } get user$() { return this._BS.asObservable().pipe( map(uf => uf.user) ); } }
Ana bileşene geri dönersek, bu eylemleri çağırmak için düğmeleri ekleyelim. Bu durumda “Kullanıcıyı Düzenle” sadece oturum açmış kullanıcı için geçerli olacaktır. Gerekirse diğer kullanıcıları düzenlemek için devam edebilir ve işlevsellik ekleyebilirsiniz!
//... <div class="d-flex justify-content-between my-3"> <h4> Me </h4> <button class="btn btn-primary" (click)="edit(user)"> Edit Profile </button> </div> //... <div class="d-flex justify-content-between my-3"> <h4> All Users </h4> <button class="btn btn-primary" (click)="create()"> New User </button> </div> //...
//... create() { this.userForm.create(); const modalRef = this.modal.open(UserFormComponent); modalRef.result.then(user => { this.userService.create(user).subscribe(_ => { console.log('user created'); }); }).catch(err => { }); } edit(userToEdit) { this.userForm.edit(userToEdit); const modalRef = this.modal.open(UserFormComponent); modalRef.result.then(user => { this.userService.edit(user).subscribe(_ => { console.log('user edited'); }); }).catch(err => { }); }
Postacıdan
Postacı, API'ler oluşturmak ve bunlara istek göndermek için kullanılan bir araçtır. Bu şekilde, API'mizi herhangi bir istemci uygulamasından veya farklı bir hizmetten çağırdığımızı simüle edebiliriz.
Demosunu yapacağımız şey, tüm kullanıcıları listelemek için nasıl istek gönderileceğidir.
Aracı açtıktan sonra, https://us-central1-{your-project}.cloudfunctions.net/api/users URL'sini belirledik:
Daha sonra yetkilendirme sekmesinde Bearer Token seçiyoruz ve daha önce Dev Tools'tan çıkardığımız değeri ayarlıyoruz.
Çözüm
Tebrikler! Tüm öğreticiyi tamamladınız ve şimdi Firebase'de kullanıcı rolü tabanlı bir API oluşturmayı öğrendiniz.
Ayrıca bir Angular uygulamasından ve Postman'den nasıl tüketileceğini de ele aldık.
En önemli şeyleri tekrarlayalım:
- Firebase, daha sonra genişletebileceğiniz kurumsal düzeyde bir yetkilendirme API'si ile hızla çalışmaya başlamanıza olanak tanır.
- Hemen hemen her proje yetkilendirme gerektirir. Rol tabanlı bir model kullanarak erişimi kontrol etmeniz gerekiyorsa, Firebase Authentication çok hızlı bir şekilde başlamanıza olanak tanır.
- Rol tabanlı model, belirli kullanıcılara karşı belirli rollere sahip kullanıcılardan talep edilen kaynakların doğrulanmasına dayanır.
- Firebase Function üzerinde bir Express.js uygulaması kullanarak, bir REST API oluşturabilir ve isteklerin kimliğini doğrulamak ve yetkilendirmek için işleyiciler ayarlayabiliriz.
- Yerleşik özel taleplerden yararlanarak, rol tabanlı bir kimlik doğrulama API'si oluşturabilir ve uygulamanızın güvenliğini sağlayabilirsiniz.
Firebase yetkilendirmesi hakkında daha fazla bilgiyi buradan edinebilirsiniz. Ve tanımladığımız rollerden yararlanmak istiyorsanız, @angular/fire helpers kullanabilirsiniz.