多租户

This commit is contained in:
COOL 2025-01-18 21:43:55 +08:00
parent 95f7218d9e
commit b165e97500
12 changed files with 141 additions and 32 deletions

View File

@ -5,8 +5,8 @@
"private": true,
"dependencies": {
"@cool-midway/core": "file:/Users/ap/Documents/src/admin/midway-packages/core",
"@cool-midway/task": "file:/Users/ap/Documents/src/admin/midway-packages/task",
"@cool-midway/rpc": "file:/Users/ap/Documents/src/admin/midway-packages/rpc",
"@cool-midway/task": "file:/Users/ap/Documents/src/admin/midway-packages/task",
"@midwayjs/bootstrap": "^3.20.0",
"@midwayjs/cache-manager": "^3.20.0",
"@midwayjs/core": "^3.20.0",

View File

@ -13,6 +13,10 @@ export default {
koa: {
port: 8001,
},
// 开启异步上下文管理
asyncContextManager: {
enable: true,
},
// 静态文件配置
staticFile: {
buffer: true,

View File

@ -28,10 +28,10 @@ export default {
// 实体与路径跟生成代码、前端请求、swagger文档相关 注意:线上不建议开启,以免暴露敏感信息
eps: true,
// 是否自动导入模块数据库
initDB: true,
initDB: false,
// 判断是否初始化的方式
initJudge: 'db',
// 是否自动导入模块菜单
initMenu: true,
initMenu: false,
} as CoolConfig,
} as MidwayConfig;

View File

@ -12,7 +12,7 @@ export default () => {
// 模块描述
description: '基础的权限管理功能,包括登录,权限校验',
// 中间件
globalMiddlewares: [BaseAuthorityMiddleware, BaseLogMiddleware],
globalMiddlewares: [BaseAuthorityMiddleware],
// 模块加载顺序默认为0值越大越优先加载
order: 10,
// app参数配置允许读取的key

View File

@ -1,34 +1,105 @@
import { EventSubscriberModel } from '@midwayjs/typeorm';
import { EntitySubscriberInterface, TransactionCommitEvent } from 'typeorm';
import { BeforeQueryEvent } from 'typeorm/subscriber/event/QueryEvent';
import {
DeleteQueryBuilder,
EntitySubscriberInterface,
InsertQueryBuilder,
SelectQueryBuilder,
UpdateQueryBuilder,
} from 'typeorm';
import * as _ from 'lodash';
import { App, IMidwayApplication } from '@midwayjs/core';
import {
App,
ASYNC_CONTEXT_KEY,
ASYNC_CONTEXT_MANAGER_KEY,
AsyncContextManager,
IMidwayApplication,
IMidwayContext,
Inject,
} from '@midwayjs/core';
/**
*
* @param ctx
* @param func
*/
export const noTenant = async (ctx, func) => {
let result;
const tenantId = ctx?.admin?.tenantId;
if (tenantId) {
ctx.admin.tenantId = null;
result = await func();
ctx.admin.tenantId = tenantId;
} else {
result = await func();
}
return result;
};
@EventSubscriberModel()
export class TenantSubscriber implements EntitySubscriberInterface<any> {
@App()
app: IMidwayApplication;
@Inject()
ctx: IMidwayContext;
/**
*
* @param event
* ID
* @returns string | undefined
*/
// @ts-ignore
beforeQuery(event: BeforeQueryEvent<any>, query: string, parameters: any[]) {
if (_.startsWith(event.query, 'SELECT')) {
console.log('event.query', this.app);
query = 'SELECT * FROM "tenant11"';
// // 参数
// const parameters = event.parameters;
// // 连接
// const queryRunner = event.connection.createQueryRunner();
// event.connection.destroy();
// // // sql语句
// // const query = event.query;
// // const queryRunner = connection.createQueryRunner();
// // 原来的event.queryRunner 干掉
// event.query = 'SELECT * FROM "tenant11"';
// throw new Error('test');
getTenantId(): number | undefined {
const contextManager: AsyncContextManager = this.app
.getApplicationContext()
.get(ASYNC_CONTEXT_MANAGER_KEY);
const ctx: any = contextManager.active().getValue(ASYNC_CONTEXT_KEY);
const url = ctx?.url;
if (_.startsWith(url, '/admin/')) {
return ctx?.admin?.tenantId;
}
}
/**
* ID条件
* @param queryBuilder
*/
afterSelectQueryBuilder(queryBuilder: SelectQueryBuilder<any>) {
const tenantId = this.getTenantId();
if (tenantId) {
queryBuilder.where('tenantId = :tenantId', { tenantId });
}
}
// /**
// * 插入时添加租户ID
// * @param queryBuilder
// */
// async afterInsertQueryBuilder(queryBuilder: InsertQueryBuilder<any>) {
// const tenantId = await this.getTenantId();
// if (tenantId) {
// queryBuilder.values({ tenantId });
// }
// }
// /**
// * 更新时添加租户ID和条件
// * @param queryBuilder
// */
// async afterUpdateQueryBuilder(queryBuilder: UpdateQueryBuilder<any>) {
// const tenantId = await this.getTenantId();
// if (tenantId) {
// queryBuilder.set({ tenantId });
// queryBuilder.where('tenantId = :tenantId', { tenantId });
// }
// }
// /**
// * 删除时添加租户ID和条件
// * @param queryBuilder
// */
// async afterDeleteQueryBuilder(queryBuilder: DeleteQueryBuilder<any>) {
// const tenantId = await this.getTenantId();
// if (tenantId) {
// queryBuilder.where('tenantId = :tenantId', { tenantId });
// }
// }
}

View File

@ -3,6 +3,7 @@ import {
UpdateDateColumn,
CreateDateColumn,
PrimaryGeneratedColumn,
Column,
} from 'typeorm';
import { CoolBaseEntity } from '@cool-midway/core';
@ -24,7 +25,7 @@ export abstract class BaseEntity extends CoolBaseEntity {
@UpdateDateColumn({ comment: '更新时间' })
updateTime: Date;
// @Index()
// @Column({ comment: '租户ID', nullable: true })
// tenantId: number;
@Index()
@Column({ comment: '租户ID', nullable: true })
tenantId: number;
}

View File

@ -51,6 +51,7 @@ export class BaseAuthorityMiddleware
if (_.startsWith(url, adminUrl)) {
try {
ctx.admin = jwt.verify(token, this.jwtConfig.jwt.secret);
ctx.admin.tenantId = 1;
if (ctx.admin.isRefresh) {
ctx.status = 401;
ctx.body = {

View File

@ -195,6 +195,7 @@ export class BaseSysLoginService extends BaseService {
username: user.username,
userId: user.id,
passwordVersion: user.passwordV,
tenantId: user['tenantId'],
};
if (isRefresh) {
tokenInfo.isRefresh = true;

View File

@ -1,5 +1,7 @@
import { CoolController, BaseController } from '@cool-midway/core';
import { DemoGoodsEntity } from '../../entity/goods';
import { Get, Inject } from '@midwayjs/core';
import { DemoGoodsService } from '../../service/goods';
/**
* -
@ -8,4 +10,13 @@ import { DemoGoodsEntity } from '../../entity/goods';
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
entity: DemoGoodsEntity,
})
export class AdminDemoGoodsController extends BaseController {}
export class AdminDemoGoodsController extends BaseController {
@Inject()
demoGoodsService: DemoGoodsService;
@Get('/test', { summary: '测试' })
async test() {
await this.demoGoodsService.test();
return this.ok('test');
}
}

View File

@ -1,6 +1,6 @@
import { DemoGoodsService } from '../../service/goods';
import { DemoGoodsEntity } from '../../entity/goods';
import { Body, Config, Inject, Post, Provide } from '@midwayjs/core';
import { Body, Config, Get, Inject, Post, Provide } from '@midwayjs/core';
import { CoolController, BaseController } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
@ -29,4 +29,10 @@ export class OpenDemoGoodsController extends BaseController {
async entityPage(@Body() query) {
return this.ok(await this.demoGoodsService.entityPage(query));
}
@Get('/test', { summary: '测试' })
async test() {
await this.demoGoodsService.test();
return this.ok('test');
}
}

View File

@ -1,8 +1,9 @@
import { DemoGoodsEntity } from './../entity/goods';
import { Provide } from '@midwayjs/core';
import { Inject, Provide } from '@midwayjs/core';
import { BaseService } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { noTenant } from '../../base/db/tenant';
/**
*
@ -12,6 +13,9 @@ export class DemoGoodsService extends BaseService {
@InjectEntityModel(DemoGoodsEntity)
demoGoodsEntity: Repository<DemoGoodsEntity>;
@Inject()
ctx;
/**
* sql分页
*/
@ -37,4 +41,14 @@ export class DemoGoodsService extends BaseService {
const find = this.demoGoodsEntity.createQueryBuilder();
return this.entityRenderPage(find, query);
}
async test() {
const a = await this.demoGoodsEntity.createQueryBuilder().getMany();
await noTenant(this.ctx, async () => {
const b = await this.demoGoodsEntity.createQueryBuilder().getMany();
console.log('b');
});
const c = await this.demoGoodsEntity.createQueryBuilder().getMany();
console.log(a);
}
}

View File

@ -38,7 +38,7 @@ export default ({ app }) => {
components: {
schemas: {},
securitySchemes: {
Auth: {
ApiKeyAuth: {
type: 'apiKey',
name: 'Authorization',
in: 'header',