You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS+TypeORM(MariaDB)配置groups表固定不可删角色

NestJS + TypeORM(MariaDB) 实现不可删除的ADMIN/DEFAULT角色

1. 确认Group实体定义

先确保你的Group实体字段配置正确,尤其是deleteable字段默认设为true(普通角色默认可删),后续给ADMIN和DEFAULT角色单独设置为false:

// src/group/group.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity('groups')
export class Group {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true }) // 保证角色名唯一,避免重复创建
  name: string;

  @Column('simple-array') // 假设权限是字符串数组,比如['create', 'read'],也可改用json类型
  permissions: string[];

  @Column({ default: true }) // 默认允许删除
  deleteable: boolean;
}

2. 自动初始化ADMIN和DEFAULT角色

在项目启动时自动创建这两个角色(如果不存在),避免手动插入。在Group服务类中实现OnModuleInit接口:

// src/group/group.service.ts
import { Injectable, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Group } from './group.entity';

@Injectable()
export class GroupService implements OnModuleInit {
  constructor(
    @InjectRepository(Group)
    private groupRepository: Repository<Group>,
  ) {}

  async onModuleInit() {
    // 检查并创建ADMIN角色
    const adminExists = await this.groupRepository.findOne({ where: { name: 'ADMIN' } });
    if (!adminExists) {
      await this.groupRepository.save({
        name: 'ADMIN',
        permissions: ['*'], // 全权限,根据业务需求调整
        deleteable: false, // 标记为不可删除
      });
    }

    // 检查并创建DEFAULT角色
    const defaultExists = await this.groupRepository.findOne({ where: { name: 'DEFAULT' } });
    if (!defaultExists) {
      await this.groupRepository.save({
        name: 'DEFAULT',
        permissions: ['read'], // 默认权限,按需调整
        deleteable: false, // 标记为不可删除
      });
    }
  }

  // 其他业务方法...
}

项目启动时会自动执行这段逻辑,重复启动也不会因为唯一约束报错。

3. 服务层控制删除逻辑

在删除角色的方法中,先判断该角色是否允许删除,若deleteable为false则拒绝操作:

// src/group/group.service.ts 新增删除方法
async deleteGroup(id: number) {
  const group = await this.groupRepository.findOne({ where: { id } });
  if (!group) {
    throw new Error('角色不存在');
  }
  if (!group.deleteable) {
    throw new Error('该角色不允许删除');
  }
  await this.groupRepository.delete(id);
}

然后在控制器中调用该方法,处理错误并返回响应:

// src/group/group.controller.ts
import { Controller, Delete, Param, HttpException, HttpStatus } from '@nestjs/common';
import { GroupService } from './group.service';

@Controller('groups')
export class GroupController {
  constructor(private readonly groupService: GroupService) {}

  @Delete(':id')
  async delete(@Param('id') id: string) {
    try {
      await this.groupService.deleteGroup(parseInt(id));
      return { message: '删除成功' };
    } catch (error) {
      throw new HttpException(error.message, HttpStatus.FORBIDDEN);
    }
  }
}

进阶:数据库层面防删除(可选)

如果担心服务层逻辑被绕过,可以在MariaDB中创建触发器,删除前检查角色名,阻止删除ADMIN和DEFAULT:

-- 执行以下SQL创建触发器
DELIMITER //
CREATE TRIGGER prevent_delete_protected_groups
BEFORE DELETE ON groups
FOR EACH ROW
BEGIN
  IF OLD.name IN ('ADMIN', 'DEFAULT') THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该角色不允许删除';
  END IF;
END //
DELIMITER ;

这个触发器会在执行DELETE操作前触发,若目标是受保护的角色则抛出错误,阻止删除。

内容的提问来源于stack exchange,提问作者luka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 05:21:05