Notadd 用户模块(GraphQL Api 版本)
模块,组织,角色,功能,权限分层(数据权限/功能权限),权限,用户
Graphql API 版: https://github.com/notadd/nt-module-user/tree/graphql-api
Rpc 版(微服务用):https://github.com/notadd/nt-module-user/tree/master
交流群:322247106
文档
功能
- [x] 注册
- [x] 登录(用户名、邮箱、手机号+验证码)
- [x] 授权、鉴权
- [x] 组织管理
- [x] 用户管理
- [x] 角色管理
- [x] 信息组管理
- [x] 信息项管理
- [x] 全局 i18n 支持
- [ ] …
使用说明
用户模块的大部分接口都定义了权限,在初始化时,会生成一个超级管理员用户,账号为: sadmin
,密码为: sadmin
,可以自行登录后,使用 accessToken
调用 updateCurrentUserInfo
(更新当前登录用户信息),修改密码。
导入用户模块
在应用程序根模块中导入 UserModule
,并配置 i18n 选项
资源定义
@Resouce
,是用户对某一实体资源进行业务操作的统称。
在 Resolver
或 Controller
类上设置定义资源的注解,用于定义当前资源,如:
@Resource({ name: '文章管理', identify: 'artical:manage' })
name
: 资源的名称,用于定义权限的父级名称,命名方式为: 资源+行为
,如:应用内文章管理的相关api => '文章管理'
identity
: 资源的唯一标识,命名方式为 模块名:类名
或 name
的拆分英文,如: '文章管理' => 'artical:manage'
权限定义
@Permission
,是用户对当前实体资源进行某一具体操作的定义。
在 Resolver
、Controller
方法上设置定义操作的注解,用户定义对当前资源的操作权限,如:
@Permission({ name: '添加文章', identify: 'artical:create', action: 'create' })
name
: 权限的名称,用于定义具体的权限名称,命名方式为:操作+资源
,如:在文章资源中添加文章 => '添加文章'
identify
: 权限的唯一标识,命名方式为:资源:方法
,如:'添加文章' => 'artical:createArtical'
action
: 权限操作类型,只能是 create、delete、update、find
中的一个
权限的定义离不开资源的定义,二者是共存的状态,在使用权限功能时,先在类上定义资源,而后在需要权限控制的方法上定义权限。
定义好资源和权限后,启动程序,资源和权限会被自动加载并存储到数据库。
配置授权,鉴权功能
以下是 apollo-server-express
2.x 版本的授权、鉴权功能逻辑示例
授权功能只需导入 UserModule
即可自动配置
app.module.ts
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from '@notadd/module-user';
@Module({
imports: [
GraphQLModule.forRootAsync({
useClass: GraphQLConfigService
}),
TypeOrmModule.forRoot(),
UserModule.forRoot({ i18n: 'zh-CN', authTokenWhiteList: [''] })
],
controllers: [],
providers: [],
exports: []
})
export class AppModule { }
Tips:
i18n
配置用于用户模块的返回消息及资源、权限注解的i18n
功能,authTokenWhiteList
可以传入字符串数组,用于配置授权白名单的接口,不配置白名单时,可不用传入authTokenWhiteList
选项
鉴权功能,在 graphql 上下文中 使用 AuthService
类的 validateUser
方法,并将通过身份验证的用户传递给上下文
GraphQLJSON
是用于处理 graphql 中的 JSON
标量类型,需要额外安装 graphql-type-json
,然后将其配置到 resolvers 选项中
graphql-config.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { GqlModuleOptions, GqlOptionsFactory } from '@nestjs/graphql';
import * as GraphQLJSON from 'graphql-type-json';
import { AuthService } from '@notadd/module-user';
@Injectable()
export class GraphQLConfigService implements GqlOptionsFactory {
constructor(
@Inject(AuthService) private readonly authService: AuthService
) {}
createGqlOptions(): GqlModuleOptions {
return {
typePaths: ['./**/*.types.graphql'],
resolvers: { JSON: GraphQLJSON },
context: async ({ req }) => {
const user = await this.authService.validateUser(req);
return { user };
}
};
}
}
接口逻辑说明
用户模块向各类上层业务系统提供了丰富且灵活的接口,以下介绍常用的接口逻辑
资源
Query:
findResources
查询所有资源权限,返回当前业务系统定义的所有资源和权限数据
角色
Query:
findRoles
查询所有角色,返回所有角色的 id 和 namefindOneRoleInfo(roleId: Int!)
查询角色信息,返回指定 id 的角色详细信息,包含角色拥有的权限及其拥有的信息项
Mutation:
createRole(name: String!)
添加角色updateRole(id: Int!, name: String!)
更新角色名称deleteRole(id: Int!)
删除指定 id 的角色setPermissionsToRole(roleId: Int!, permissionIds: [Int]!)
给角色设置权限
信息组
Query:
findAllInfoGroup
查询所有信息组findInfoItemsByGroupId(groupId: Int!)
查询指定信息组下的所有信息项
Mutation:
createInfoGroup(name: String!, roleId: Int!)
新增信息组deleteInfoGroup(groupId: Int!)
删除指定ID的信息组updateInfoGroup(groupId: Int!, name: String, roleId: Int)
更新指定ID的信息组名称或所属角色addInfoItemToInfoGroup(infoGroupId: Int!, infoItemIds: [Int]!)
向指定信息组添加指定信息项deleteIntoItemFromInfoGroup(infoGroupId: Int!, infoItemIds: [Int]!)
删除指定信息组的指定信息项
信息项
Query:
findAllInfoItem
查询所有信息项
Mutation:
createInfoItem(infoItemInput: InfoItemInput)
新增信息项deleteInfoItem(infoItemId: Int!)
删除指定ID的信息项updateInfoItem(updateInfoItemInput: UpdateInfoItemInput)
更新指定ID的信息项名称、标签、描述、类型
组织
Query:
findRootOrganizations
获取根组织findAllOrganizations
获取所有组织findChildrenOrganizations(id: Int!)
获取指定组织下的所有子组织
Mutation:
createOrganization(name: String!, parentId: Int)
创建组织,parentId 为空时,代表创建根组织updateOrganization(id: Int!, name: String!, parentId: Int!)
更新组织deleteOrganization(id: Int!)
删除组织addUsersToOrganization(id: Int!, userIds: [Int]!)
给组织添加用户deleteUserFromOrganization(id: Int!, userIds: [Int]!)
删除组织下的用户
用户
Query:
login(username: String!, password: String!)
普通用户登录adminLogin(username: String!, password: String!)
管理员登录findRegisterUserInfoItem
查询普通用户注册时所需填写的信息项findCurrentUserInfo
查询当前登录的用户信息findUserInfoByIds(userIds: [Int]!)
通过ID查询用户信息findUsersInRole(roleId: Int!)
查询指定角色ID下的所有用户信息findUsersInOrganization(organizationId: Int!)
获取指定组织ID下的用户
注意:手机号+验证码方式的登录使用的是腾讯云短信服务,需提前调用
sms
相关接口进行短信服务的配置
Mutation:
register(registerUserInput: RegisterUserInput)
普通用户注册,参数 infoKVs 中的 key 是信息项的ID(infoItem.id),值是信息项的值(userInfo.value)createUser(createUserInput: CreateUserInput)
创建用户,参数 infoKVs 中的 key 是信息项的ID(infoItem.id),值是信息项的值(userInfo.value)addUserRole(userId: Int!, roleId: Int!)
给用户添加角色banUser(userId: Int!)
封禁用户deleteUserRole(userId: Int!, roleId: Int!)
删除用户角色recycleUser(userId: Int!)
删除用户到回收站deleteRecycledUser(userId: Int!)
删除回收站内的用户revertBannedUser(userId: Int!)
恢复封禁的用户revertRecycledUser(userId: Int!)
恢复回收站内的用户updateUserInfoById(userId: Int!, updateUserInput: UpdateUserInput)
更新用户信息,参数 infoKVs 中的 key是用户信息项值的ID(userInfo.id),value是信息项的值(userInfo.value),relationId 是信息项的ID,当返回的 key 为 null 时,也需要传入 nullupdateCurrentUserInfo(updateCurrentUserInput: UpdateCurrentUserInput)
更新当前登录用户信息,参数 infoKVs 中的 key是用户信息项值的ID(userInfo.id),value是信息项的值(userInfo.value),relationId 是信息项的ID,当返回的 key 为 null 时,也需要传入 null
顶
很不错,专业,还提供rpc接口 From Noder
@axetroy 微服务,当然得提供哈
@zuohuadong 数据库ER图能画出来学习下嘛?
文档部分在完善,如果需要哪方面的,请告知,会优先写相关文档