開発中のアプリでデータ共有で招待QRコードを発行して、スキャンでゲストログインできる仕組みを実装したので記事化
PR
実装の概要
- backend/アプリのゲストログインの実装
- ゲストユーザーログインのトークンを発行してHeaderに設定して認証するミドルウェアを実装
- QRコード作成/スキャン
- QRコード作成: qr_flutter
- QRコードスキャン: mobile_scanner
- QRコードをスキャンした時にアプリに指定の動作をさせる
実装
まず、backendのゲストログインの実装 詳しいtable設計は省略するが、以下のように認証のコードを修正
■ typescript/backend/src/common/guards/auth/auth.guard.ts
const authorization = request.headers.authorization if (!authorization) { throw new Error('Authorization header not found') } if (authorization?.startsWith('Bearer ')) { const token = authorization.split('Bearer ')[1] const result = await admin.auth().verifyIdToken(token) const user = await this.prisma.user.findFirst({ where: { uid: result.uid, }, }) if (!user) { throw new Error('User not found') } request.auth = { guest: false, uid: user.uid, userId: user.id, user: user, } as Auth } else if (authorization?.startsWith('Guest ')) { const guestUid = authorization.split('Guest ')[1] const guest = await this.prisma.guest.findFirst({ where: { uid: guestUid, }, }) if (!guest) { throw new Error('Guest not found') } const user = await this.prisma.user.findFirst({ where: { id: guest.userId, }, }) if (!user) { throw new Error('User not found') } request.auth = { guest: true, guestUId: guestUid, uid: user.uid, userId: user.id, user: user, } as Auth }
HeaderのAuthorization
の値がBearer xxxxxx
の場合はFirebaseで認証、Guest xxxxxx
の場合はゲストログインとして自前のdbと検索して認証を行い、招待されたユーザーのデータをAPI上で参照できるようにする。この仕組みを作った上で次にアプリを実装
アプリでは招待する側は招待用のQRコードを qr_flutterを使用して生成
コードは以下のように実装
■dart/app/lib/features/category/components/share/bottomSheet.dart
final inviteURL = "https://stock-keeper-review.web.app/guest/login/${code.value}"; return Padding( padding: const EdgeInsets.only( top: Spacing.md, bottom: Spacing.xl, left: Spacing.md, right: Spacing.md), (省略) child: loading ? const Progress( color: AppColors.textDark, ) : QrImageView( data: inviteURL, // ← dataにURLを設定 version: QrVersions.auto, size: 125.0, ), )),
QrImageView
のdataには前回の記事で紹介したユニバーサルリンク/アプリリンクの設定をしたURLを指定
go_routerで上記のURLを指定した時にゲストログインの画面に遷移できるように修正
final goRouter = GoRouter( initialLocation: '/', routes: [ GoRoute( path: '/', name: "home", pageBuilder: (context, state) { return MaterialPage(key: state.pageKey, child: const AuthWrapper()); }, routes: [ GoRoute( path: "guest/login/:code", // ← ゲストログインできる画面 name: "guest_login", pageBuilder: (context, state) { final code = state.pathParameters['code']!; return BottomSheetPage(builder: (_) => ShareBottomSheet(code: code)); }, ),
この実装でアプリでQRコードスキャンアプリでスキャンした時にゲストログイン動作の実装は完了
最後にアプリ内にも招待QRコードのスキャンの画面を実装してアプリ内からもゲストログインを可能にする
flutterでQRコードのスキャンは mobile_scannerを使用
コードは以下のように実装
■dart/app/lib/features/login/components/bottomSheet.dart
void onScan(BarcodeCapture capture) { final List<Barcode> barcodes = capture.barcodes; final value = barcodes.first.rawValue; // valueでQRコードの値を取得 // 省略 } return Padding( padding: const EdgeInsets.only( top: Spacing.md, bottom: Spacing.xl, left: Spacing.md, right: Spacing.md), (省略) child: SizedBox( height: 200, width: 200, child: MobileScanner( controller: MobileScannerController( detectionSpeed: DetectionSpeed .noDuplicates, // 同じ QR コードを連続でスキャンさせない ), onDetect: onScan, // ← ここがQRコードスキャンのハンドラー )),
この実装でアプリ内でQRコードをスキャンした時にゲストログイン動作の実装も完了
最後
現状の実装だとゲストログインのセキュリティが甘いので、最終的にはFirebase App Checkまで実装して機能的には完成の予定