library-picturebook-activity/backend/docs/RBAC_EXAMPLES.md
2025-11-23 14:04:20 +08:00

11 KiB
Raw Permalink Blame History

RBAC 权限控制使用示例

📋 目录

  1. 基础使用
  2. 角色控制示例
  3. 权限控制示例
  4. 完整示例

🔧 基础使用

1. 创建权限

// 在数据库中创建权限
const permissions = [
  { code: 'user:create', resource: 'user', action: 'create', name: '创建用户' },
  { code: 'user:read', resource: 'user', action: 'read', name: '查看用户' },
  { code: 'user:update', resource: 'user', action: 'update', name: '更新用户' },
  { code: 'user:delete', resource: 'user', action: 'delete', name: '删除用户' },
  { code: 'role:create', resource: 'role', action: 'create', name: '创建角色' },
  { code: 'role:read', resource: 'role', action: 'read', name: '查看角色' },
];

for (const perm of permissions) {
  await prisma.permission.create({ data: perm });
}

2. 创建角色并分配权限

// 创建管理员角色
const adminRole = await prisma.role.create({
  data: {
    name: '管理员',
    code: 'admin',
    permissions: {
      create: [
        { permission: { connect: { code: 'user:create' } } },
        { permission: { connect: { code: 'user:read' } } },
        { permission: { connect: { code: 'user:update' } } },
        { permission: { connect: { code: 'user:delete' } } },
        { permission: { connect: { code: 'role:create' } } },
        { permission: { connect: { code: 'role:read' } } },
      ]
    }
  }
});

// 创建编辑角色(只有查看和更新权限)
const editorRole = await prisma.role.create({
  data: {
    name: '编辑',
    code: 'editor',
    permissions: {
      create: [
        { permission: { connect: { code: 'user:read' } } },
        { permission: { connect: { code: 'user:update' } } },
      ]
    }
  }
});

3. 给用户分配角色

// 给用户分配管理员角色
await prisma.userRole.create({
  data: {
    user: { connect: { id: 1 } },
    role: { connect: { code: 'admin' } }
  }
});

// 用户可以有多个角色
await prisma.userRole.create({
  data: {
    user: { connect: { id: 1 } },
    role: { connect: { code: 'editor' } }
  }
});

🎯 角色控制示例

在控制器中使用角色装饰器

import { Controller, Get, Post, Delete, UseGuards } from '@nestjs/common';
import { Roles } from '../auth/decorators/roles.decorator';
import { RolesGuard } from '../auth/guards/roles.guard';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';

@Controller('users')
@UseGuards(JwtAuthGuard, RolesGuard)  // 先验证 JWT再验证角色
export class UsersController {
  
  // 所有已登录用户都可以查看
  @Get()
  findAll() {
    return this.usersService.findAll();
  }
  
  // 只有管理员和编辑可以创建用户
  @Post()
  @Roles('admin', 'editor')
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
  
  // 只有管理员可以删除用户
  @Delete(':id')
  @Roles('admin')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

🔐 权限控制示例

创建权限守卫(可选扩展)

// src/auth/guards/permissions.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class PermissionsGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
      'permissions',
      [context.getHandler(), context.getClass()],
    );

    if (!requiredPermissions) {
      return true; // 没有权限要求,允许访问
    }

    const { user } = context.switchToHttp().getRequest();
    const userPermissions = user.permissions || [];
    
    // 检查用户是否拥有任一所需权限
    return requiredPermissions.some((permission) =>
      userPermissions.includes(permission),
    );
  }
}

创建权限装饰器

// src/auth/decorators/permissions.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const PERMISSIONS_KEY = 'permissions';
export const Permissions = (...permissions: string[]) =>
  SetMetadata(PERMISSIONS_KEY, permissions);

使用权限控制

import { Controller, Get, Post, Delete, UseGuards } from '@nestjs/common';
import { Permissions } from '../auth/decorators/permissions.decorator';
import { PermissionsGuard } from '../auth/guards/permissions.guard';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';

@Controller('users')
@UseGuards(JwtAuthGuard, PermissionsGuard)
export class UsersController {
  
  @Get()
  @Permissions('user:read')  // 需要 user:read 权限
  findAll() {
    return this.usersService.findAll();
  }
  
  @Post()
  @Permissions('user:create')  // 需要 user:create 权限
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
  
  @Delete(':id')
  @Permissions('user:delete')  // 需要 user:delete 权限
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

📚 完整示例

完整的用户管理控制器

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Query,
  UseGuards,
  Request,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';

@Controller('users')
@UseGuards(JwtAuthGuard)  // 所有接口都需要登录
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  // 查看用户列表 - 所有已登录用户都可以访问
  @Get()
  findAll(@Query('page') page?: string, @Query('pageSize') pageSize?: string) {
    return this.usersService.findAll(
      page ? parseInt(page) : 1,
      pageSize ? parseInt(pageSize) : 10,
    );
  }

  // 查看用户详情 - 所有已登录用户都可以访问
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

  // 创建用户 - 需要 admin 或 editor 角色
  @Post()
  @UseGuards(RolesGuard)
  @Roles('admin', 'editor')
  create(@Body() createUserDto: CreateUserDto, @Request() req) {
    // req.user 包含当前用户信息(从 JWT 中提取)
    return this.usersService.create(createUserDto);
  }

  // 更新用户 - 需要 admin 角色,或者用户自己更新自己
  @Patch(':id')
  @UseGuards(RolesGuard)
  async update(
    @Param('id') id: string,
    @Body() updateUserDto: UpdateUserDto,
    @Request() req,
  ) {
    const userId = parseInt(id);
    const currentUserId = req.user.userId;
    
    // 管理员可以更新任何人,普通用户只能更新自己
    if (req.user.roles?.includes('admin') || userId === currentUserId) {
      return this.usersService.update(userId, updateUserDto);
    }
    
    throw new ForbiddenException('无权更新此用户');
  }

  // 删除用户 - 只有管理员可以删除
  @Delete(':id')
  @UseGuards(RolesGuard)
  @Roles('admin')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

🔍 权限检查流程

1. 用户登录

// POST /api/auth/login
{
  "username": "admin",
  "password": "password123"
}

// 返回
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 1,
    "username": "admin",
    "nickname": "管理员",
    "roles": ["admin"],  // 用户的角色列表
    "permissions": [     // 用户的所有权限(从角色中聚合)
      "user:create",
      "user:read",
      "user:update",
      "user:delete",
      "role:create",
      "role:read"
    ]
  }
}

2. 访问受保护的接口

// 请求头
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

// 流程
1. JwtAuthGuard 验证 Token
   └─> 提取用户信息,添加到 req.user

2. RolesGuard 检查角色
   └─>  req.user.roles 中检查是否包含所需角色
   └─> 如果包含,允许访问;否则返回 403 Forbidden

🎨 前端权限控制示例

Vue 3 中使用权限

// stores/auth.ts
export const useAuthStore = defineStore('auth', () => {
  const user = ref<User | null>(null);
  
  // 检查是否有指定角色
  const hasRole = (role: string) => {
    return user.value?.roles?.includes(role) ?? false;
  };
  
  // 检查是否有指定权限
  const hasPermission = (permission: string) => {
    return user.value?.permissions?.includes(permission) ?? false;
  };
  
  // 检查是否有任一角色
  const hasAnyRole = (roles: string[]) => {
    return roles.some(role => hasRole(role));
  };
  
  // 检查是否有任一权限
  const hasAnyPermission = (permissions: string[]) => {
    return permissions.some(perm => hasPermission(perm));
  };
  
  return {
    user,
    hasRole,
    hasPermission,
    hasAnyRole,
    hasAnyPermission,
  };
});

在组件中使用

<template>
  <div>
    <!-- 根据角色显示按钮 -->
    <a-button v-if="authStore.hasRole('admin')" @click="deleteUser">
      删除用户
    </a-button>
    
    <!-- 根据权限显示按钮 -->
    <a-button v-if="authStore.hasPermission('user:create')" @click="createUser">
      创建用户
    </a-button>
    
    <!-- 根据角色或权限显示 -->
    <a-button 
      v-if="authStore.hasAnyRole(['admin', 'editor']) || authStore.hasPermission('user:update')"
      @click="editUser"
    >
      编辑用户
    </a-button>
  </div>
</template>

<script setup lang="ts">
import { useAuthStore } from '@/stores/auth';

const authStore = useAuthStore();
</script>

路由守卫

// router/index.ts
router.beforeEach((to, from, next) => {
  const authStore = useAuthStore();
  
  // 检查是否需要认证
  if (to.meta.requiresAuth && !authStore.isAuthenticated) {
    next({ name: 'Login' });
    return;
  }
  
  // 检查角色
  if (to.meta.roles && !authStore.hasAnyRole(to.meta.roles)) {
    next({ name: 'Forbidden' });
    return;
  }
  
  // 检查权限
  if (to.meta.permissions && !authStore.hasAnyPermission(to.meta.permissions)) {
    next({ name: 'Forbidden' });
    return;
  }
  
  next();
});

📊 权限矩阵示例

角色 user:create user:read user:update user:delete role:create role:read
admin
editor
viewer

🎯 总结

RBAC 权限控制的核心是:

  1. 用户 ←→ 角色 ←→ 权限
  2. 通过 @Roles() 装饰器控制接口访问
  3. 前端根据返回的 rolespermissions 控制 UI 显示
  4. 权限由 resource:action 组成,如 user:create

这样的设计既保证了安全性,又提供了良好的灵活性和可维护性!