umimax+nest.js 实现 权限管理系统

前端

umi文档 ,在文档中你可以看到,有一个权限配置,它有一套自己的权限管理方案

定义权限

约定`src/access.ts`` 为权限定义文件,判断是否具有某个权限

image-20240325095054783

路由权限

在你的路由配置中 增加一个字段access,则会判断路由是否有权限,例如

image-20240325094731789

功能权限

使用useAccess获取权限,可以获取到你定义的所有权限

image-20240325095159867

何时来获取用户权限信息

约定在src/app.tsx 下导出一个方法getInitialState,可以初始化信息.例如

export async function getInitialState(): Promise<{
  user_info?: API.UserInfo;
  roles?: any[];
}> {
  let user_info;
  let roleList;
  const fetchUserInfo = async () => {
    try {
      const token = localStorage.getItem('token');
      const user_info = JSON.parse(localStorage.getItem('user_info') || '');
      if (!token || !user_info) {
        history.push('/login');
      }
      return { token, user_info };
    } catch (error) {
      history.push('/login');
    }
    return { token: null, user_info: null };
  };
  if (history.location.pathname !== '/login') {
    const res = await fetchUserInfo();
    const { roles, ...reset } = res.user_info;
    user_info = reset;
    roleList = roles;
  }
  return {
    user_info,
    roles: roleList,
  };
}

上述代码,我在初始化时判断是否为登陆页,来获取存储的信息(权限) ,但是 这个信息初始化后 如果登陆信息发生改变,则需要重新让它获取最新的登陆信息,所以我们在登陆的时候,让它重新初始化

import { useModel} from '@umijs/max';

const { refresh } = useModel('@@initialState');
const handleLogin = async (values: any) => {
  const res = await login(values);
  if (res.data) {
    const { token, user_info } = res.data;
    localStorage.setItem('token', token);
    localStorage.setItem('user_info', JSON.stringify(user_info));
    navigate('/');
    refresh();
  }
};

在登陆成功后,更新本地缓存并且重新初始化,即可获取用户最新的权限

后端

用户=>角色=>权限

用户、角色、权限三个表互相关联

数据库

user.entity.ts

import { Role } from 'src/role/entities/role.entity';
import { Column, Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';

@Entity({
  name: 'user',
})
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({
    comment: '姓名',
    length: 50,
  })
  name: string;

  @Column({
    comment: '密码',
    length: 50,
  })
  password: string;

  @Column({
    comment: '头像',
    length: 1000,
    default: 'https://p26-passport.byteacctimg.com/img/user-avatar/312989b46037c16843b1eb44aea82fa2~180x180.awebp?',
  })
  avator: string;

  @Column({
    comment: '手机号',
    length: 50,
    default:""
  })
  mobile: string;

  @ManyToMany(() => Role)
  @JoinTable({
    name: 'user_role_relation',
  })
  roles: Role[]; //角色

  @Column({
    comment: '是否可用',
    default: true,
  })
  state: boolean;
}

role.entity.ts

//role.entity.ts
import {
    Column,
    CreateDateColumn,
    Entity,
    JoinTable,
    ManyToMany,
    PrimaryGeneratedColumn,
    UpdateDateColumn,
  } from 'typeorm';
  import { Permission } from '../../permission/entities/permission.entity';
  @Entity()
  export class Role {
    @PrimaryGeneratedColumn()
    id: string;
  
    @Column({
      length: 20,
    })
    name: string;
  
    @CreateDateColumn()
    createTime: Date;
  
    @UpdateDateColumn()
    updateTime: Date;
  
    @ManyToMany(() => Permission)
    @JoinTable({
      name: 'role_permission_relation',
    })
    permissions: Permission[];
  }
  

permission.entity.ts

//permission.entity.ts
import {
    Column,
    CreateDateColumn,
    Entity,
    PrimaryGeneratedColumn,
    UpdateDateColumn,
  } from 'typeorm';
  
  @Entity()
  export class Permission {
    @PrimaryGeneratedColumn()
    id: string;
  
    @Column({
      length: 50,
    })
    name: string;
  
    @Column({
      length: 100,
      nullable: true,
    })
    desc: string;

    @CreateDateColumn()
    createTime: Date;
  
    @UpdateDateColumn()
    updateTime: Date;
  }
  

定义好三个表后就差不多好了

在查询用户信息时,我也需要查询到用户的角色和权限

 this.userRepository.findOne({
      where: { id, state: true },
      select: ['name', 'avator', 'id', 'mobile'],
      relations: ['roles', 'roles.permissions'],
    });

更新用户 角色

async updateUserRoles(createRoleDto) {
    const id = createRoleDto.userId;

    const user = await this.findOne(id);
    if (!user) {
      throw new UnauthorizedException('用户名不存在');
    }
    console.log(user);

    //查询传入数组roles的全部role实体
    const roles = await this.roleRepository.findBy({
      id: In(createRoleDto.roleIds),
    });
    user.roles = roles
    if (roles.length <= 0) {
      throw new Error('roles not found');
    }

    return this.userRepository.save(user);
  }

权限和角色的查询和修改同用户表一致,如此一来权限控制就实现了

总结

这是我的后台管理系统(umimax+nest+mysql)的权限设计,以此学习后端和数据库知识,还有docker及自动化部署,感兴趣可以一起学习

最后更新于

这有帮助吗?