NestJSでRBAC Permission Systemを設計する:ステップバイステップガイド
Takashi Yamamoto
Infrastructure Engineer · Leapcell

Preface
バックエンド管理システムでは、アクセス制御やパーソナライズされたユーザーインターフェースなどの機能が不可欠です。たとえば、スーパー管理者はすべてのページを表示でき、通常のユーザーはページAとBにアクセスでき、VIPユーザーはページA、B、C、Dを表示できます。これらの機能の背後にあるロジックは、次の3つの主要な概念の設計に基づいています。
- User: 基本的な単位(アリス、ボブ、チャーリーなど)。
- Role: ユーザーは1つまたは複数のロールを持つことができます。たとえば、アリスは通常のユーザーとVIPの両方のロールを持つことができます。
- Permission: ロールは複数の権限に関連付けられています。たとえば、VIPロールは表示、編集、追加の権限を持ち、スーパー管理者は表示、編集、追加、削除の権限を持つことができます。
この関係は、次の図で示すことができます。
次に、Nest
を使用して、このようなシステムの基盤をゼロから実装します — 権限設計。
Creating the Database
まず、データベースを作成する必要があります。MySQL
データベースを使用し、次のコマンドを実行して作成します。
CREATE DATABASE `nest-database` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Project Initialization
次のコマンドを実行して、新しいNest
プロジェクトを開始します。
nest new nest-project
次に、必要なデータベースの依存関係(主にtypeorm
とmysql2
)をインストールします。
npm install --save @nestjs/typeorm typeorm mysql2
次に、app.module.ts
でtypeorm
を設定します。
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'password', database: 'nest-database', synchronize: true, logging: true, entities: [__dirname + '/**/*.entity{.ts,.js}'], poolSize: 10, connectorPackage: 'mysql2', }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Table Design
通常、RBAC(ロールベースのアクセス制御)システムには、次の5つのテーブルがあります。
- User table (
user
): ユーザー名、パスワード、メールなどの基本的なユーザー情報を保存します。 - Role table (
role
): ロール名やロールコードなどのロールの詳細を保存します。 - Permission table (
permission
): 権限名や権限コードなどの権限の詳細を保存します。 - User-role relation table (
user_role_relation
): ユーザーとロールの間の関係を追跡します。 - Role-permission relation table (
role_permission_relation
): ロールと権限の間の関係を追跡します。
ドメインモデルは、次のように視覚化できます。
次に、Nest
で3つの非リレーションテーブルを作成し、それらの関係を定義します。
user.entity.ts
:
import { Column, CreateDateColumn, Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; import { Role } from './role.entity'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column({ length: 50, }) username: string; @Column({ length: 50, }) password: string; @CreateDateColumn() createTime: Date; @UpdateDateColumn() updateTime: Date; @ManyToMany(() => Role) @JoinTable({ name: 'user_role_relation', joinColumn: { name: 'userId', referencedColumnName: 'id', }, inverseJoinColumn: { name: 'roleId', referencedColumnName: 'id', }, }) roles: Role[]; }
User
テーブルでは、roles
フィールドはuser_role_relation
テーブルとの接続を定義するために使用されます。関係ロジックは、user.id === userRoleRelation.userId
とrole.id === userRoleRelation.roleId
です。一致するRole
レコードは、自動的にUser
にリンクされます。
role.entity.ts
:
import { Column, CreateDateColumn, Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; import { Permission } from './permission.entity'; @Entity() export class Role { @PrimaryGeneratedColumn() id: number; @Column({ length: 20, }) name: string; @CreateDateColumn() createTime: Date; @UpdateDateColumn() updateTime: Date; @ManyToMany(() => Permission) @JoinTable({ name: 'role_permission_relation', joinColumn: { name: 'roleId', referencedColumnName: 'id', }, inverseJoinColumn: { name: 'permissionId', referencedColumnName: 'id', }, }) permissions: Permission[]; }
Roleテーブルのpermissions
フィールドも同様に機能します。これは、role.id === rolePermissionRelation.roleId
とpermission.id === rolePermissionRelation.permissionId
のロジックを使用して、role_permission_relation
テーブルに接続します。
permission.entity.ts
:
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; @Entity() export class Permission { @PrimaryGeneratedColumn() id: number; @Column({ length: 50, }) name: string; @Column({ length: 100, nullable: true, }) desc: string; @CreateDateColumn() createTime: Date; @UpdateDateColumn() updateTime: Date; }
Permissionテーブルには関係がありません。単に使用可能な権限を記録します。
Data Initialization
テストデータを初期化するサービスを次に示します。
async function initData() { const user1 = new User(); user1.username = 'Alice'; user1.password = 'aaaaaa'; const user2 = new User(); user2.username = 'Bob'; user2.password = 'bbbbbb'; const user3 = new User(); user3.username = 'Charlie'; user3.password = 'cccccc'; const role1 = new Role(); role1.name = 'Administrator'; const role2 = new Role(); role2.name = 'Regular User'; const permission1 = new Permission(); permission1.name = 'Add resource_a'; const permission2 = new Permission(); permission2.name = 'Edit resource_a'; const permission3 = new Permission(); permission3.name = 'Delete resource_a'; const permission4 = new Permission(); permission4.name = 'Query resource_a'; const permission5 = new Permission(); permission5.name = 'Add resource_b'; const permission6 = new Permission(); permission6.name = 'Edit resource_b'; const permission7 = new Permission(); permission7.name = 'Delete resource_b'; const permission8 = new Permission(); permission8.name = 'Query resource_b'; role1.permissions = [ permission1, permission2, permission3, permission4, permission5, permission6, permission7, permission8, ]; role2.permissions = [permission1, permission2, permission3, permission4]; user1.roles = [role1]; user2.roles = [role2]; await this.entityManager.save(Permission, [ permission1, permission2, permission3, permission4, permission5, permission6, permission7, permission8, ]); await this.entityManager.save(Role, [role1, role2]); await this.entityManager.save(User, [user1, user2]); }
ブラウザまたはPostmanを介してinitData
サービスを実行すると、データがデータベースに投入されます。
基本的な権限構造が設定されたので、登録、ログイン、JWTベースの認証などの機能を実装できます。
さあ、あなたの番です!
Leapcellは、NestJSプロジェクトをクラウドにデプロイするための最高の選択肢です。
Leapcellは、Webホスティング、非同期タスク、Redisのための次世代サーバーレスプラットフォームです。
Multi-Language Support
- JavaScript、Python、Go、またはRustで開発します。
Deploy unlimited projects for free
- 使用量に対してのみ支払い — リクエストなし、料金なし。
Unbeatable Cost Efficiency
- アイドル料金なしの従量課金。
- 例:25ドルで、平均応答時間60msで694万リクエストをサポートします。
Streamlined Developer Experience
- 楽なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムのメトリックとロギング。
Effortless Scalability and High Performance
- 高い同時実行性を容易に処理するための自動スケーリング。
- 運用上のオーバーヘッドはゼロ — 構築に集中するだけです。
ドキュメントで詳細をご覧ください!
Xでフォローしてください:@LeapcellHQ