Firebase認証を使用してロールベースのAPIを構築する方法
公開: 2022-03-11このチュートリアルでは、FirebaseとNode.jsを使用してユーザーとロールを管理するRESTAPIを構築します。 さらに、APIを使用して、特定のリソースにアクセスできるユーザーを承認する(または承認しない)方法についても説明します。
序章
ほとんどすべてのアプリには、ある程度の認証システムが必要です。 ユーザーテーブルで設定されたユーザー名/パスワードを検証するだけで十分な場合もありますが、多くの場合、特定のユーザーが特定のリソースにアクセスして他のリソースから制限できるように、よりきめ細かい権限モデルが必要です。 後者をサポートするシステムを構築することは簡単ではなく、非常に時間がかかる可能性があります。 このチュートリアルでは、Firebaseを使用してロールベースの認証APIを構築する方法を学習します。これにより、すばやく起動して実行できるようになります。
役割ベースの認証
この承認モデルでは、特定のユーザーではなくロールにアクセスが許可され、ユーザーは、アクセス許可モデルの設計方法に応じて1つ以上のユーザーを持つことができます。 一方、リソースには、ユーザーがリソースを実行できるようにするための特定のロールが必要です。
Firebase
Firebase認証
簡単に言うと、Firebase Authenticationは拡張可能なトークンベースの認証システムであり、Google、Facebook、Twitterなどの最も一般的なプロバイダーとすぐに統合できます。
これにより、柔軟なロールベースのAPIを構築するために活用するカスタムクレームを使用できます。
クレームには任意のJSON値を設定できます(例{ role: 'admin' }
または{ role: 'manager' }
)。
設定すると、Firebaseが生成するトークンにカスタムクレームが含まれ、値を読み取ってアクセスを制御できます。
また、非常に寛大な無料の割り当てが付属しており、ほとんどの場合、これで十分です。
Firebaseの機能
関数は、フルマネージドのサーバーレスプラットフォームサービスです。 Node.jsにコードを記述してデプロイするだけです。 Firebaseは、インフラストラクチャのオンデマンドのスケーリング、サーバー構成などを処理します。 この例では、これを使用してAPIを構築し、HTTP経由でWebに公開します。
Firebaseを使用すると、 express.js
アプリをさまざまなパスのハンドラーとして設定できます。たとえば、Expressアプリを作成して/mypath
にフックすると、このルートに着信するすべてのリクエストは、構成されたapp
によって処理されます。
関数のコンテキスト内から、Admin SDKを使用して、FirebaseAuthenticationAPI全体にアクセスできます。
これがユーザーAPIの作成方法です。
構築するもの
始める前に、何を構築するかを見てみましょう。 次のエンドポイントを使用してRESTAPIを作成します。
Http動詞 | 道 | 説明 | 承認 |
---|---|---|---|
得る | / users | すべてのユーザーを一覧表示します | 管理者とマネージャーのみがアクセスできます |
役職 | / users | 新しいユーザーを作成します | 管理者とマネージャーのみがアクセスできます |
得る | / users /:id | :idユーザーを取得します | 管理者、管理者、および:idと同じユーザーがアクセスできます |
パッチ | / users /:id | :idユーザーを更新します | 管理者、管理者、および:idと同じユーザーがアクセスできます |
消去 | / users /:id | :idユーザーを削除します | 管理者、管理者、および:idと同じユーザーがアクセスできます |
これらの各エンドポイントは、認証を処理し、承認を検証し、対応する操作を実行し、最後に意味のあるHTTPコードを返します。
トークンを検証し、操作を実行するために必要な役割がクレームに含まれているかどうかを確認するために必要な認証および承認機能を作成します。
APIの構築
APIを構築するには、次のものが必要です。
- Firebaseプロジェクト
firebase-tools
がインストールされています
まず、Firebaseにログインします。
firebase login
次に、Functionsプロジェクトを初期化します。
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
この時点で、FirebaseFunctionsを作成するための最小限のセットアップを備えたFunctionsフォルダーが作成されます。
src/index.ts
にhelloWorld
の例があり、コメントを外して関数が機能することを検証できます。 次に、 cd functions
して、 npm run serve
できます。 このコマンドは、コードをトランスパイルし、ローカルサーバーを起動します。
結果はhttp:// localhost:5000 / {your-project} / us-central1/helloWorldで確認できます。
関数は、 'index.ts: 'helloWorld'
でその名前として定義されたパスに公開されていることに注意してください。
FirebaseHTTP関数の作成
それでは、APIをコーディングしましょう。 http Firebase関数を作成し、それを/api
パスにフックします。
まず、 npm install express
ます。
src/index.ts
で、次のことを行います。
-
admin.initializeApp();
を使用してfirebase-adminSDKモジュールを初期化します。 - Expressアプリを
api
エンドポイントのハンドラーとして設定します
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);
これで、 /api
に送信されるすべてのリクエストはapp
インスタンスによって処理されます。
次に行うことは、CORSをサポートするようにapp
インスタンスを構成し、JSONボディパーサーミドルウェアを追加することです。 このようにして、任意のURLからリクエストを作成し、JSON形式のリクエストを解析できます。
まず、必要な依存関係をインストールします。
npm install --save cors body-parser
npm install --save-dev @types/cors
その後:
//... 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);
最後に、 app
が処理するルートを構成します。
//... import { routesConfig } from './users/routes-config'; //… app.use(cors({ origin: true })); routesConfig(app) export const api = functions.https.onRequest(app);
Firebase Functionsを使用すると、Expressアプリをハンドラーとして設定したり、 functions.https.onRequest(app);
—この場合、 api
—もapp
によって処理されます。 これにより、 api/users
などの特定のエンドポイントを記述し、次に行うHTTP動詞ごとにハンドラーを設定できます。
ファイルsrc/users/routes-config.ts
を作成しましょう
ここでは、 POST '/users'
にcreate
ハンドラーを設定します
import { Application } from "express"; import { create} from "./controller"; export function routesConfig(app: Application) { app.post('/users', create ); }
次に、 src/users/controller.ts
ファイルを作成します。
この関数では、最初にすべてのフィールドが本文リクエストに含まれていることを検証し、次にユーザーを作成してカスタムクレームを設定します。
setCustomUserClaims
で{ role }
を渡すだけです。他のフィールドはFirebaseによってすでに設定されています。
エラーが発生しない場合は、作成されたユーザーのuid
を含む201コードを返します。
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}` }); }
それでは、承認を追加してハンドラーを保護しましょう。 そのために、 create
エンドポイントにいくつかのハンドラーを追加します。 express.js
を使用すると、順番に実行されるハンドラーのチェーンを設定できます。 ハンドラー内で、コードを実行してnext()
ハンドラーに渡すか、応答を返すことができます。 まずユーザーを認証してから、実行が許可されているかどうかを検証します。
ファイルsrc/users/routes-config.ts
:
//... 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
ファイルを作成しましょう。
この関数では、リクエストヘッダーにauthorization
ベアラートークンが存在することを検証します。 次に、 admin.auth().verifyidToken()
を使用してデコードし、ユーザーのuid
、 role
、およびemail
をres.locals
変数に保持します。これは、後で承認の検証に使用します。
トークンが無効な場合、クライアントに401応答を返します。
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' }); } }
それでは、 src/auth/authorized.ts
ファイルを作成しましょう。
このハンドラーでは、以前に設定したres.locals
からユーザーの情報を抽出し、操作の実行に必要な役割があるかどうかを検証します。操作で同じユーザーが実行できる場合は、リクエストパラメーターのIDを検証します。 authトークンのものと同じです。 ユーザーが必要な役割を持っていない場合は、403を返します。
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(); } }
これらの2つの方法を使用すると、リクエストを認証し、着信トークンでのrole
を指定してリクエストを承認することができます。 これはすばらしいことですが、Firebaseではプロジェクトコンソールからカスタムクレームを設定できないため、これらのエンドポイントを実行することはできません。 これを回避するために、Firebase認証コンソールからrootユーザーを作成できます
そして、コードに電子メールの比較を設定します。 これで、このユーザーからリクエストを送信すると、すべての操作を実行できるようになります。
//... const { role, email, uid } = res.locals const { id } = req.params if (email === '[email protected]') return next(); //...
それでは、残りのCRUD操作をsrc/users/routes-config.ts
に追加しましょう。
:id
paramが送信される単一のユーザーを取得または更新する操作の場合、同じユーザーが操作を実行することも許可されます。
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 ]); }
そして、 src/users/controller.ts
にあります。 これらの操作では、管理SDKを利用してFirebase認証とやり取りし、それぞれの操作を実行します。 以前にcreate
操作で行ったように、各操作で意味のあるHTTPコードを返します。
更新操作では、存在するすべてのフィールドを検証し、 customClaims
をリクエストで送信されたフィールドでオーバーライドします。
//.. 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) } } //...
これで、関数をローカルで実行できます。 そのためには、まず、認証APIにローカルで接続できるようにアカウントキーを設定する必要があります。 次に、以下を実行します。
npm run serve
APIをデプロイします
すごい! ロールベースのAPIを作成したので、それをWebにデプロイして使用を開始できます。 Firebaseを使用したデプロイは非常に簡単です。必要なのは、 firebase deploy
を実行することだけです。 デプロイが完了すると、公開されたURLでAPIにアクセスできます。
API URLは、https://console.firebase.google.com/u/0/project/{your-project}/functions/listで確認できます。

私の場合は[https://us-central1-joaq-lab.cloudfunctions.net/api]です。
APIの使用
APIをデプロイしたら、それを使用するいくつかの方法があります。このチュートリアルでは、PostmanまたはAngularアプリからAPIを使用する方法について説明します。
任意のブラウザで[すべてのユーザーのリスト]URL( /api/users
)を入力すると、次のようになります。
これは、ブラウザからリクエストを送信するときに、認証ヘッダーなしでGETリクエストを実行しているためです。 これは、APIが実際に期待どおりに機能していることを意味します。
APIはトークンを介して保護されています。このようなトークンを生成するには、FirebaseのクライアントSDKを呼び出し、有効なユーザー/パスワードのクレデンシャルでログインする必要があります。 成功すると、Firebaseは応答でトークンを送り返します。トークンは、実行する後続のリクエストのヘッダーに追加できます。
Angularアプリから
このチュートリアルでは、AngularアプリからAPIを使用するための重要な部分について説明します。 完全なリポジトリにはここからアクセスできます。Angularアプリを作成し、使用するように@ angle / fireを構成する方法についてのステップバイステップのチュートリアルが必要な場合は、この投稿を確認できます。
したがって、サインインに戻ると、ユーザーがユーザー名とパスワードを入力できるようにするための<form>
を備えたSignInComponent
があります。
//... <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> //...
そして、クラスでは、 AngularFireAuth
サービスを使用してsignInWithEmailAndPassword
を実行します。
//... 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) } } //..
この時点で、Firebaseプロジェクトにログインできます。
また、DevToolsでネットワークリクエストを調べると、Firebaseがユーザーとパスワードを確認した後にトークンを返すことがわかります。
このトークンは、作成したAPIにヘッダーのリクエストを送信するために使用するトークンです。 すべてのリクエストにトークンを追加する1つの方法は、 HttpInterceptor
を使用することです。
このファイルは、 AngularFireAuth
からトークンを取得し、それをヘッダーのリクエストに追加する方法を示しています。 次に、AppModuleでインターセプターファイルを提供します。
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 { }
インターセプターが設定されると、 httpClient
からAPIにリクエストを送信できます。 たとえば、これがUsersService
で、すべてのユーザーのリストを呼び出し、IDでユーザーを取得し、ユーザーを作成して、ユーザーを更新します。
//… 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) } }
これで、APIを呼び出して、ログインしているユーザーをIDで取得し、次のようなコンポーネントからすべてのユーザーを一覧表示できます。
//... <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)) ) } //...
そして、これが結果です。
role=user
のユーザーでサインインすると、Meセクションのみがレンダリングされることに注意してください。
そして、ネットワークインスペクターで403を取得します。 これは、「管理者」がすべてのユーザーを一覧表示できるようにするためにAPIで以前に設定した制限によるものです。
それでは、「ユーザーの作成」と「ユーザーの編集」機能を追加しましょう。 そのために、最初にUserFormComponent
とUserFormService
を作成しましょう。
<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) ); } }
メインコンポーネントに戻って、これらのアクションを呼び出すためのボタンを追加しましょう。 この場合、「ユーザーの編集」はログインしたユーザーのみが利用できます。 必要に応じて、先に進んで他のユーザーを編集する機能を追加できます。
//... <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 => { }); }
郵便配達員から
Postmanは、APIを構築してリクエストするためのツールです。 このようにして、任意のクライアントアプリまたは別のサービスからAPIを呼び出していることをシミュレートできます。
デモするのは、すべてのユーザーを一覧表示するリクエストを送信する方法です。
ツールを開いたら、URL https:// us-central1- {your-project} .cloudfunctions.net / api/usersを設定します。
次に、タブ認証で、Bearer Tokenを選択し、以前にDevToolsから抽出した値を設定します。
結論
おめでとう! チュートリアル全体を完了し、FirebaseでユーザーロールベースのAPIを作成する方法を学びました。
また、AngularアプリとPostmanからそれを利用する方法についても説明しました。
最も重要なことを要約しましょう:
- Firebaseを使用すると、エンタープライズレベルの認証APIをすばやく起動して実行できます。このAPIは、後で拡張できます。
- ほとんどすべてのプロジェクトで承認が必要です。役割ベースのモデルを使用してアクセスを制御する必要がある場合、FirebaseAuthenticationを使用すると非常に迅速に開始できます。
- 役割ベースのモデルは、特定の役割を持つユーザーと特定のユーザーから要求されたリソースの検証に依存しています。
- Firebase FunctionでExpress.jsアプリを使用すると、REST APIを作成し、リクエストを認証および承認するためのハンドラーを設定できます。
- 組み込みのカスタムクレームを活用して、役割ベースの認証APIを作成し、アプリを保護できます。
Firebase認証について詳しくは、こちらをご覧ください。 また、定義した役割を活用したい場合は、@ angle/fireヘルパーを使用できます。