mirror of
https://github.com/cool-team-official/cool-admin-midway.git
synced 2026-02-08 11:25:36 +00:00
完善了权限管理功能
This commit is contained in:
parent
832dd68f30
commit
046940e2e8
5
.vscode/middleware.code-snippets
vendored
5
.vscode/middleware.code-snippets
vendored
@ -3,7 +3,8 @@
|
|||||||
"prefix": "middleware",
|
"prefix": "middleware",
|
||||||
"body": [
|
"body": [
|
||||||
"import { Provide } from '@midwayjs/decorator';",
|
"import { Provide } from '@midwayjs/decorator';",
|
||||||
"import { IWebMiddleware, IMidwayWebNext, IMidwayWebContext } from '@midwayjs/web';",
|
"import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web';",
|
||||||
|
"import { Context } from 'egg';",
|
||||||
"",
|
"",
|
||||||
"/**",
|
"/**",
|
||||||
" * 描述",
|
" * 描述",
|
||||||
@ -12,7 +13,7 @@
|
|||||||
"export class XxxMiddleware implements IWebMiddleware {",
|
"export class XxxMiddleware implements IWebMiddleware {",
|
||||||
"",
|
"",
|
||||||
" resolve() {",
|
" resolve() {",
|
||||||
" return async (ctx: IMidwayWebContext, next: IMidwayWebNext) => {",
|
" return async (ctx: Context, next: IMidwayWebNext) => {",
|
||||||
" // 控制器前执行的逻辑",
|
" // 控制器前执行的逻辑",
|
||||||
" const startTime = Date.now();",
|
" const startTime = Date.now();",
|
||||||
" // 执行下一个 Web 中间件,最后执行到控制器",
|
" // 执行下一个 Web 中间件,最后执行到控制器",
|
||||||
|
|||||||
@ -1,32 +1,31 @@
|
|||||||
|
import { Provide } from '@midwayjs/decorator';
|
||||||
import * as ipdb from 'ipip-ipdb';
|
import * as ipdb from 'ipip-ipdb';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
import { Context } from 'egg';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 帮助类
|
* 帮助类
|
||||||
*/
|
*/
|
||||||
export default class Helper {
|
@Provide()
|
||||||
/**
|
export class Helper {
|
||||||
* 获得请求IP
|
/**
|
||||||
*/
|
* 获得请求IP
|
||||||
public static async getReqIP() {
|
*/
|
||||||
// @ts-ignore
|
public async getReqIP(ctx: Context) {
|
||||||
const req = this.ctx.req;
|
const req = ctx.req;
|
||||||
return (req.headers['x-forwarded-for'] || // 判断是否有反向代理 IP
|
return req.headers['x-forwarded-for'] || req.socket.remoteAddress
|
||||||
req.connection.remoteAddress || // 判断 connection 的远程 IP
|
|
||||||
req.socket.remoteAddress || // 判断后端的 socket 的 IP
|
|
||||||
req.connection.socket.remoteAddress).replace('::ffff:', '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据IP获得请求地址
|
* 根据IP获得请求地址
|
||||||
* @param ip 为空时则为当前请求的IP地址
|
* @param ip 为空时则为当前请求的IP地址
|
||||||
*/
|
*/
|
||||||
public static async getIpAddr(ip?: string) {
|
public async getIpAddr(ctx: Context, ip?: string | string[]) {
|
||||||
try {
|
try {
|
||||||
if (!ip) {
|
if (!ip) {
|
||||||
ip = await this.getReqIP();
|
ip = await this.getReqIP(ctx);
|
||||||
}
|
}
|
||||||
const bst = new ipdb.BaseStation('app/resource/ipip/ipipfree.ipdb');
|
const bst = new ipdb.BaseStation('./ipipfree.ipdb');
|
||||||
const result = bst.findInfo(ip, 'CN');
|
const result = bst.findInfo(ip, 'CN');
|
||||||
const addArr: any = [];
|
const addArr: any = [];
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -35,7 +34,7 @@ export default class Helper {
|
|||||||
addArr.push(result.cityName);
|
addArr.push(result.cityName);
|
||||||
return _.uniq(addArr).join('');
|
return _.uniq(addArr).join('');
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return '无法获取地址信息';
|
return '无法获取地址信息';
|
||||||
}
|
}
|
||||||
@ -45,7 +44,7 @@ export default class Helper {
|
|||||||
* 去除对象的空值属性
|
* 去除对象的空值属性
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
public static async removeEmptyP (obj) {
|
public async removeEmptyP(obj) {
|
||||||
Object.keys(obj).forEach(key => {
|
Object.keys(obj).forEach(key => {
|
||||||
if (obj[key] === null || obj[key] === '' || obj[key] === 'undefined') {
|
if (obj[key] === null || obj[key] === '' || obj[key] === 'undefined') {
|
||||||
delete obj[key];
|
delete obj[key];
|
||||||
@ -57,7 +56,7 @@ export default class Helper {
|
|||||||
* 线程阻塞毫秒数
|
* 线程阻塞毫秒数
|
||||||
* @param ms
|
* @param ms
|
||||||
*/
|
*/
|
||||||
public static sleep(ms) {
|
public sleep(ms) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,6 @@ export default (app: Application) => {
|
|||||||
// 模块描述
|
// 模块描述
|
||||||
describe: '基础的权限管理功能,包括登录,权限校验',
|
describe: '基础的权限管理功能,包括登录,权限校验',
|
||||||
// 中间件
|
// 中间件
|
||||||
middlewares: ['baseLogsMiddleware'],
|
middlewares: ['baseLogMiddleware', 'baseAuthorityMiddleware'],
|
||||||
} as ModuleConfig;
|
} as ModuleConfig;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { Body, Provide, ALL, Inject, Post, Get, Query } from '@midwayjs/decorator';
|
import { Provide, Inject, Get } from '@midwayjs/decorator';
|
||||||
|
import { Context } from 'egg';
|
||||||
import { CoolController, BaseController } from 'midwayjs-cool-core';
|
import { CoolController, BaseController } from 'midwayjs-cool-core';
|
||||||
import { LoginDTO } from '../../dto/login';
|
import { BaseSysPermsService } from '../../service/sys/perms';
|
||||||
import { BaseSysLoginService } from '../../service/sys/login';
|
import { BaseSysUserService } from '../../service/sys/user';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base 通用接口 一般写不需要权限过滤的接口
|
* Base 通用接口 一般写不需要权限过滤的接口
|
||||||
@ -11,23 +12,28 @@ import { BaseSysLoginService } from '../../service/sys/login';
|
|||||||
export class BaseCommController extends BaseController {
|
export class BaseCommController extends BaseController {
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
baseSysLoginService: BaseSysLoginService;
|
baseSysUserService: BaseSysUserService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysPermsService: BaseSysPermsService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 获得个人信息
|
||||||
* @param login
|
|
||||||
*/
|
*/
|
||||||
@Post('/login')
|
@Get('/person')
|
||||||
async login(@Body(ALL) login: LoginDTO) {
|
public async person() {
|
||||||
return this.ok(await this.baseSysLoginService.login(login))
|
return this.ok(await this.baseSysUserService.person());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得验证码
|
* 权限菜单
|
||||||
*/
|
*/
|
||||||
@Get('/captcha')
|
@Get('/permmenu')
|
||||||
async captcha(@Query() type: string, @Query() width: number, @Query() height: number) {
|
public async permmenu() {
|
||||||
return this.ok(await this.baseSysLoginService.captcha(type, width, height));
|
return this.ok(await this.baseSysPermsService.permmenu(this.ctx.admin.roleIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
40
src/app/modules/base/controller/admin/open.ts
Normal file
40
src/app/modules/base/controller/admin/open.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Provide, Body, ALL, Inject, Post, Get, Query } from '@midwayjs/decorator';
|
||||||
|
import { CoolController, BaseController } from 'midwayjs-cool-core';
|
||||||
|
import { LoginDTO } from '../../dto/login';
|
||||||
|
import { BaseSysLoginService } from '../../service/sys/login';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不需要登录的后台接口
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@CoolController()
|
||||||
|
export class BaseSysOpenController extends BaseController {
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysLoginService: BaseSysLoginService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
* @param login
|
||||||
|
*/
|
||||||
|
@Post('/login')
|
||||||
|
async login(@Body(ALL) login: LoginDTO) {
|
||||||
|
return this.ok(await this.baseSysLoginService.login(login))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得验证码
|
||||||
|
*/
|
||||||
|
@Get('/captcha')
|
||||||
|
async captcha(@Query() type: string, @Query() width: number, @Query() height: number) {
|
||||||
|
return this.ok(await this.baseSysLoginService.captcha(type, width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
*/
|
||||||
|
@Get('/refreshToken')
|
||||||
|
async refreshToken(@Query() refreshToken: string) {
|
||||||
|
return this.ok(await this.baseSysLoginService.refreshToken(refreshToken))
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/app/modules/base/controller/admin/sys/department.ts
Normal file
29
src/app/modules/base/controller/admin/sys/department.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ALL, Body, Inject, Post, Provide } from '@midwayjs/decorator';
|
||||||
|
import { CoolController, BaseController } from 'midwayjs-cool-core';
|
||||||
|
import { BaseSysDepartmentEntity } from '../../../entity/sys/department';
|
||||||
|
import { BaseSysDepartmentService } from '../../../service/sys/department';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@CoolController({
|
||||||
|
api: ['add', 'delete', 'update', 'list'],
|
||||||
|
entity: BaseSysDepartmentEntity,
|
||||||
|
service: BaseSysDepartmentService
|
||||||
|
})
|
||||||
|
export class BaseDepartmentController extends BaseController {
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseDepartmentService: BaseSysDepartmentService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门排序
|
||||||
|
*/
|
||||||
|
@Post('/order')
|
||||||
|
async order(@Body(ALL) params: Object) {
|
||||||
|
await this.baseDepartmentService.order(params);
|
||||||
|
this.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/app/modules/base/controller/admin/sys/menu.ts
Normal file
20
src/app/modules/base/controller/admin/sys/menu.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Inject, Provide } from '@midwayjs/decorator';
|
||||||
|
import { CoolController, BaseController } from 'midwayjs-cool-core';
|
||||||
|
import { BaseSysMenuEntity } from '../../../entity/sys/menu';
|
||||||
|
import { BaseSysMenuService } from '../../../service/sys/menu';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@CoolController({
|
||||||
|
api: ['add', 'delete', 'update', 'list', 'page'],
|
||||||
|
entity: BaseSysMenuEntity,
|
||||||
|
service: BaseSysMenuService
|
||||||
|
})
|
||||||
|
export class BaseSysMenuController extends BaseController {
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysMenuService: BaseSysMenuService;
|
||||||
|
|
||||||
|
}
|
||||||
@ -26,4 +26,8 @@ export class BaseSysLogEntity extends BaseEntity {
|
|||||||
|
|
||||||
@Column({ comment: '参数', nullable: true, type: 'text' })
|
@Column({ comment: '参数', nullable: true, type: 'text' })
|
||||||
params: string;
|
params: string;
|
||||||
|
|
||||||
|
@Column({ comment: '响应毫秒数, 值为-1则响应不成功', default: -1 })
|
||||||
|
ms: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
105
src/app/modules/base/middleware/authority.ts
Normal file
105
src/app/modules/base/middleware/authority.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { Config, Inject, Provide } from '@midwayjs/decorator';
|
||||||
|
import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import { CoolCache, CoolConfig, RESCODE } from 'midwayjs-cool-core';
|
||||||
|
import * as jwt from 'jsonwebtoken';
|
||||||
|
import { Context } from 'egg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
export class BaseAuthorityMiddleware implements IWebMiddleware {
|
||||||
|
|
||||||
|
@Config('cool')
|
||||||
|
coolConfig: CoolConfig;
|
||||||
|
|
||||||
|
@Inject('cool:cache')
|
||||||
|
coolCache: CoolCache;
|
||||||
|
|
||||||
|
resolve() {
|
||||||
|
return async (ctx: Context, next: IMidwayWebNext) => {
|
||||||
|
let statusCode = 200;
|
||||||
|
const { url } = ctx;
|
||||||
|
const token = ctx.get('Authorization');
|
||||||
|
let { prefix } = this.coolConfig.router;
|
||||||
|
const adminUrl = prefix ? `${prefix}/admin/` : '/admin/';
|
||||||
|
// 只要登录每个人都有权限的接口
|
||||||
|
const commUrl = prefix ? `${prefix}/admin/comm/` : '/admin/comm/';
|
||||||
|
// 不需要登录的接口
|
||||||
|
const openUrl = prefix ? `${prefix}/admin/open/` : '/admin/open/';
|
||||||
|
// 路由地址为 admin前缀的 需要权限校验
|
||||||
|
if (_.startsWith(url, adminUrl)) {
|
||||||
|
try {
|
||||||
|
ctx.admin = jwt.verify(token, this.coolConfig.jwt.secret);
|
||||||
|
} catch (err) { }
|
||||||
|
// comm 不需要登录 无需权限校验
|
||||||
|
if (_.startsWith(url, openUrl)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ctx.admin) {
|
||||||
|
if (_.startsWith(url, commUrl)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果传的token是refreshToken则校验失败
|
||||||
|
if (ctx.admin.isRefresh) {
|
||||||
|
ctx.status = 401;
|
||||||
|
ctx.body = {
|
||||||
|
code: RESCODE.COMMFAIL,
|
||||||
|
message: '登录失效~',
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断密码版本是否正确
|
||||||
|
const passwordV = await this.coolCache.get(`admin:passwordVersion:${ctx.admin.userId}`);
|
||||||
|
if (passwordV !== ctx.admin.passwordVersion) {
|
||||||
|
ctx.status = 401;
|
||||||
|
ctx.body = {
|
||||||
|
code: RESCODE.COMMFAIL,
|
||||||
|
message: '登录失效~',
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rToken = await this.coolCache.get(`admin:token:${ctx.admin.userId}`);
|
||||||
|
if (!rToken) {
|
||||||
|
ctx.status = 401;
|
||||||
|
ctx.body = {
|
||||||
|
code: RESCODE.COMMFAIL,
|
||||||
|
message: '登录失效或无权限访问~',
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rToken !== token && this.coolConfig.sso) {
|
||||||
|
statusCode = 401;
|
||||||
|
} else {
|
||||||
|
let perms = await this.coolCache.get(`admin:perms:${ctx.admin.userId}`);
|
||||||
|
if (!_.isEmpty(perms)) {
|
||||||
|
perms = JSON.parse(perms).map(e => {
|
||||||
|
return e.replace(/:/g, '/');
|
||||||
|
});
|
||||||
|
if (!perms.includes(url.split('?')[0].replace('/admin/', ''))) {
|
||||||
|
statusCode = 403;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
statusCode = 403;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
statusCode = 401;
|
||||||
|
}
|
||||||
|
if (statusCode > 200) {
|
||||||
|
ctx.status = statusCode;
|
||||||
|
ctx.body = {
|
||||||
|
code: RESCODE.COMMFAIL,
|
||||||
|
message: '登录失效或无权限访问~',
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,21 +1,21 @@
|
|||||||
import { Provide } from '@midwayjs/decorator';
|
import { Inject, Provide } from '@midwayjs/decorator';
|
||||||
import { IWebMiddleware, IMidwayWebNext, IMidwayWebContext } from '@midwayjs/web';
|
import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web';
|
||||||
|
import { BaseSysLogService } from '../service/sys/log';
|
||||||
|
import { Context } from 'egg';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志中间件
|
* 日志中间件
|
||||||
*/
|
*/
|
||||||
@Provide()
|
@Provide()
|
||||||
export class BaseLogsMiddleware implements IWebMiddleware {
|
export class BaseLogMiddleware implements IWebMiddleware {
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysLogService: BaseSysLogService;
|
||||||
|
|
||||||
resolve() {
|
resolve() {
|
||||||
return async (ctx: IMidwayWebContext, next: IMidwayWebNext) => {
|
return async (ctx: Context, next: IMidwayWebNext) => {
|
||||||
console.log('日志')
|
this.baseSysLogService.record(ctx.url.split('?')[0], ctx.req.method === 'GET' ? ctx.request.query : ctx.request.body, ctx.admin ? ctx.admin.userId : null);
|
||||||
// 控制器前执行的逻辑
|
|
||||||
const startTime = Date.now();
|
|
||||||
// 执行下一个 Web 中间件,最后执行到控制器
|
|
||||||
await next();
|
await next();
|
||||||
// 控制器之后执行的逻辑
|
|
||||||
console.log(Date.now() - startTime);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { Provide } from '@midwayjs/decorator';
|
import { Inject, Provide } from '@midwayjs/decorator';
|
||||||
import { BaseService } from 'midwayjs-cool-core';
|
import { BaseService } from 'midwayjs-cool-core';
|
||||||
import { InjectEntityModel } from '@midwayjs/orm';
|
import { InjectEntityModel } from '@midwayjs/orm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { BaseSysDepartmentEntity } from '../../entity/sys/department';
|
import { BaseSysDepartmentEntity } from '../../entity/sys/department';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { BaseSysRoleDepartmentEntity } from '../../entity/sys/role_department';
|
import { BaseSysRoleDepartmentEntity } from '../../entity/sys/role_department';
|
||||||
|
import { Context } from 'egg';
|
||||||
|
import { BaseSysPermsService } from './perms';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 描述
|
* 描述
|
||||||
@ -18,6 +20,42 @@ export class BaseSysDepartmentService extends BaseService {
|
|||||||
@InjectEntityModel(BaseSysRoleDepartmentEntity)
|
@InjectEntityModel(BaseSysRoleDepartmentEntity)
|
||||||
baseSysRoleDepartmentEntity: Repository<BaseSysRoleDepartmentEntity>;
|
baseSysRoleDepartmentEntity: Repository<BaseSysRoleDepartmentEntity>;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysPremsService: BaseSysPermsService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得部门菜单
|
||||||
|
*/
|
||||||
|
async list () {
|
||||||
|
const permsDepartmentArr = await this.baseSysPremsService.departmentIds(this.ctx.admin.userId); // 部门权限
|
||||||
|
const departments = await this.nativeQuery(`
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
base_sys_department a
|
||||||
|
WHERE
|
||||||
|
1 = 1
|
||||||
|
${ this.setSql(this.ctx.decoded.userId !== '1', 'and a.id in (?)', [ !_.isEmpty(permsDepartmentArr) ? permsDepartmentArr : [ null ] ]) }
|
||||||
|
ORDER BY
|
||||||
|
a.orderNum ASC`);
|
||||||
|
if (!_.isEmpty(departments)) {
|
||||||
|
departments.forEach(e => {
|
||||||
|
const parentMenu = departments.filter(m => {
|
||||||
|
if (e.parentId === m.id) {
|
||||||
|
return m.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!_.isEmpty(parentMenu)) {
|
||||||
|
e.parentName = parentMenu[0].name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return departments;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据多个ID获得部门权限信息
|
* 根据多个ID获得部门权限信息
|
||||||
* @param {[]} roleIds 数组
|
* @param {[]} roleIds 数组
|
||||||
@ -40,4 +78,31 @@ export class BaseSysDepartmentService extends BaseService {
|
|||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门排序
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
async order (params) {
|
||||||
|
for (const e of params) {
|
||||||
|
await this.baseSysDepartmentEntity.update(e.id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
async delete (ids: number[]) {
|
||||||
|
let { deleteUser } = this.ctx.request.body;
|
||||||
|
await this.baseSysDepartmentEntity.delete(ids);
|
||||||
|
if (deleteUser) {
|
||||||
|
await this.nativeQuery('delete from base_sys_user where departmentId in (?)', [ ids ]);
|
||||||
|
} else {
|
||||||
|
const topDepartment = await this.baseSysDepartmentEntity.createQueryBuilder().where('parentId is null').getOne();
|
||||||
|
if (topDepartment) {
|
||||||
|
await this.nativeQuery('update base_sys_user a set a.departmentId = ? where a.departmentId in (?)', [ topDepartment.id, ids ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6,6 +6,7 @@ import { Context } from 'egg';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { BaseSysLogEntity } from '../../entity/sys/log';
|
import { BaseSysLogEntity } from '../../entity/sys/log';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
import { Helper } from '../../../../extend/helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 描述
|
* 描述
|
||||||
@ -16,6 +17,9 @@ export class BaseSysLogService extends BaseService {
|
|||||||
@Inject()
|
@Inject()
|
||||||
ctx: Context;
|
ctx: Context;
|
||||||
|
|
||||||
|
// @Inject()
|
||||||
|
// helper: Helper;
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysLogEntity)
|
@InjectEntityModel(BaseSysLogEntity)
|
||||||
baseSysLogEntity: Repository<BaseSysLogEntity>;
|
baseSysLogEntity: Repository<BaseSysLogEntity>;
|
||||||
|
|
||||||
@ -26,18 +30,18 @@ export class BaseSysLogService extends BaseService {
|
|||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
*/
|
*/
|
||||||
async record(url, params, userId) {
|
async record(url, params, userId) {
|
||||||
const ip = await this.ctx.helper.getReqIP();
|
// const ip = await this.helper.getReqIP(this.ctx);
|
||||||
const sysLog = new BaseSysLogEntity();
|
// const sysLog = new BaseSysLogEntity();
|
||||||
sysLog.userId = userId;
|
// sysLog.userId = userId;
|
||||||
sysLog.ip = ip;
|
// sysLog.ip = ip;
|
||||||
const ipAddrArr = new Array();
|
// const ipAddrArr = new Array();
|
||||||
for (const e of ip.split(',')) ipAddrArr.push(await this.ctx.helper.getIpAddr(e));
|
// for (const e of ip.split(',')) ipAddrArr.push(await this.ctx.helper.getIpAddr(e));
|
||||||
sysLog.ipAddr = ipAddrArr.join(',');
|
// sysLog.ipAddr = ipAddrArr.join(',');
|
||||||
sysLog.action = url;
|
// sysLog.action = url;
|
||||||
if (!_.isEmpty(params)) {
|
// if (!_.isEmpty(params)) {
|
||||||
sysLog.params = JSON.stringify(params);
|
// sysLog.params = JSON.stringify(params);
|
||||||
}
|
// }
|
||||||
await this.baseSysLogEntity.insert(sysLog);
|
// await this.baseSysLogEntity.insert(sysLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Inject, Provide, Config } from '@midwayjs/decorator';
|
import { Inject, Provide, Config } from '@midwayjs/decorator';
|
||||||
import { BaseService, CoolCache, CoolCommException } from 'midwayjs-cool-core';
|
import { BaseService, CoolCache, CoolCommException, CoolConfig, RESCODE } from 'midwayjs-cool-core';
|
||||||
import { LoginDTO } from '../../dto/login';
|
import { LoginDTO } from '../../dto/login';
|
||||||
import * as svgCaptcha from 'svg-captcha';
|
import * as svgCaptcha from 'svg-captcha';
|
||||||
import * as svgToDataURL from 'svg-to-dataurl';
|
import * as svgToDataURL from 'svg-to-dataurl';
|
||||||
@ -13,6 +13,7 @@ import * as _ from 'lodash';
|
|||||||
import { BaseSysMenuService } from './menu';
|
import { BaseSysMenuService } from './menu';
|
||||||
import { BaseSysDepartmentService } from './department';
|
import { BaseSysDepartmentService } from './department';
|
||||||
import * as jwt from 'jsonwebtoken';
|
import * as jwt from 'jsonwebtoken';
|
||||||
|
import { Context } from 'egg';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
@ -24,7 +25,7 @@ export class BaseSysLoginService extends BaseService {
|
|||||||
coolCache: CoolCache;
|
coolCache: CoolCache;
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysUserEntity)
|
@InjectEntityModel(BaseSysUserEntity)
|
||||||
baseSysLogEntity: Repository<BaseSysUserEntity>;
|
baseSysUserEntity: Repository<BaseSysUserEntity>;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
baseSysRoleService: BaseSysRoleService;
|
baseSysRoleService: BaseSysRoleService;
|
||||||
@ -35,8 +36,11 @@ export class BaseSysLoginService extends BaseService {
|
|||||||
@Inject()
|
@Inject()
|
||||||
baseSysDepartmentService: BaseSysDepartmentService;
|
baseSysDepartmentService: BaseSysDepartmentService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
|
||||||
@Config('cool')
|
@Config('cool')
|
||||||
coolConfig;
|
coolConfig: CoolConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
@ -46,7 +50,7 @@ export class BaseSysLoginService extends BaseService {
|
|||||||
const { username, captchaId, verifyCode, password } = login;
|
const { username, captchaId, verifyCode, password } = login;
|
||||||
const checkV = await this.captchaCheck(captchaId, verifyCode);
|
const checkV = await this.captchaCheck(captchaId, verifyCode);
|
||||||
if (checkV) {
|
if (checkV) {
|
||||||
const user = await this.baseSysLogEntity.findOne({ username });
|
const user = await this.baseSysUserEntity.findOne({ username });
|
||||||
if (user) {
|
if (user) {
|
||||||
if (user.status === 0 || user.password !== md5(password)) {
|
if (user.status === 0 || user.password !== md5(password)) {
|
||||||
throw new CoolCommException('账户或密码不正确~');
|
throw new CoolCommException('账户或密码不正确~');
|
||||||
@ -59,12 +63,12 @@ export class BaseSysLoginService extends BaseService {
|
|||||||
throw new CoolCommException('该用户未设置任何角色,无法登录~');
|
throw new CoolCommException('该用户未设置任何角色,无法登录~');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { expire, refreshExpire } = this.coolConfig.token.jwt;
|
const { expire, refreshExpire } = this.coolConfig.jwt.token;
|
||||||
const result = {
|
const result = {
|
||||||
expire,
|
expire,
|
||||||
token: await this.generateToken(user, roleIds, expire),
|
token: await this.generateToken(user, roleIds, expire),
|
||||||
refreshExpire,
|
refreshExpire,
|
||||||
refreshToken: await this.generateToken(user, roleIds, refreshExpire),
|
refreshToken: await this.generateToken(user, roleIds, refreshExpire, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
const perms = await this.baseSysMenuService.getPerms(roleIds);
|
const perms = await this.baseSysMenuService.getPerms(roleIds);
|
||||||
@ -111,11 +115,11 @@ export class BaseSysLoginService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检验图片验证码
|
* 检验图片验证码
|
||||||
* @param captchaId 验证码ID
|
* @param captchaId 验证码ID
|
||||||
* @param value 验证码
|
* @param value 验证码
|
||||||
*/
|
*/
|
||||||
public async captchaCheck(captchaId, value) {
|
async captchaCheck(captchaId, value) {
|
||||||
const rv = await this.coolCache.get(`verify:img:${captchaId}`);
|
const rv = await this.coolCache.get(`verify:img:${captchaId}`);
|
||||||
if (!rv || !value || value.toLowerCase() !== rv) {
|
if (!rv || !value || value.toLowerCase() !== rv) {
|
||||||
return false;
|
return false;
|
||||||
@ -137,16 +141,40 @@ export class BaseSysLoginService extends BaseService {
|
|||||||
const tokenInfo = {
|
const tokenInfo = {
|
||||||
isRefresh: false,
|
isRefresh: false,
|
||||||
roleIds,
|
roleIds,
|
||||||
|
username: user.username,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
passwordVersion: user.passwordV,
|
passwordVersion: user.passwordV,
|
||||||
};
|
};
|
||||||
if (isRefresh) {
|
if (isRefresh) {
|
||||||
delete tokenInfo.roleIds;
|
|
||||||
tokenInfo.isRefresh = true;
|
tokenInfo.isRefresh = true;
|
||||||
}
|
}
|
||||||
return jwt.sign(tokenInfo,
|
return jwt.sign(tokenInfo,
|
||||||
this.coolConfig.token.jwt.secret, {
|
this.coolConfig.jwt.secret, {
|
||||||
expiresIn: expire,
|
expiresIn: expire,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
* @param token
|
||||||
|
*/
|
||||||
|
async refreshToken(token: string) {
|
||||||
|
try {
|
||||||
|
const decoded = jwt.verify(token, this.coolConfig.jwt.secret);
|
||||||
|
if (decoded && decoded['isRefresh']) {
|
||||||
|
return jwt.sign(decoded,
|
||||||
|
this.coolConfig.jwt.secret, {
|
||||||
|
expiresIn: this.coolConfig.jwt.token.expire,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.ctx.status = 401;
|
||||||
|
this.ctx.body = {
|
||||||
|
code: RESCODE.COMMFAIL,
|
||||||
|
message: '登录失效~',
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ export class BaseSysMenuService extends BaseService {
|
|||||||
* 获得所有菜单
|
* 获得所有菜单
|
||||||
*/
|
*/
|
||||||
async list() {
|
async list() {
|
||||||
const menus = await this.getMenus(this.ctx.admin.roleIds);
|
const menus = await this.getMenus(this.ctx.admin.roleIds, this.ctx.admin.username === 'admin');
|
||||||
if (!_.isEmpty(menus)) {
|
if (!_.isEmpty(menus)) {
|
||||||
menus.forEach(e => {
|
menus.forEach(e => {
|
||||||
const parentMenu = menus.filter(m => {
|
const parentMenu = menus.filter(m => {
|
||||||
@ -46,8 +46,8 @@ export class BaseSysMenuService extends BaseService {
|
|||||||
let perms = [];
|
let perms = [];
|
||||||
if (!_.isEmpty(roleIds)) {
|
if (!_.isEmpty(roleIds)) {
|
||||||
const result = await this.nativeQuery(`
|
const result = await this.nativeQuery(`
|
||||||
SELECT a.perms FROM sys_menu a ${this.setSql(!roleIds.includes('1'),
|
SELECT a.perms FROM base_sys_menu a ${this.setSql(!roleIds.includes('1'),
|
||||||
'JOIN sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])}
|
'JOIN base_sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])}
|
||||||
where 1=1 and a.perms is not NULL
|
where 1=1 and a.perms is not NULL
|
||||||
`, [roleIds]);
|
`, [roleIds]);
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -68,14 +68,15 @@ export class BaseSysMenuService extends BaseService {
|
|||||||
/**
|
/**
|
||||||
* 获得用户菜单信息
|
* 获得用户菜单信息
|
||||||
* @param roleIds
|
* @param roleIds
|
||||||
|
* @param isAdmin 是否是超管
|
||||||
*/
|
*/
|
||||||
async getMenus(roleIds) {
|
async getMenus(roleIds, isAdmin) {
|
||||||
return await this.nativeQuery(`
|
return await this.nativeQuery(`
|
||||||
SELECT
|
SELECT
|
||||||
a.*
|
a.*
|
||||||
FROM
|
FROM
|
||||||
sys_menu a
|
base_sys_menu a
|
||||||
${this.setSql(!roleIds.includes('1'), 'JOIN sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])}
|
${this.setSql(!isAdmin, 'JOIN base_sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])}
|
||||||
GROUP BY a.id
|
GROUP BY a.id
|
||||||
ORDER BY
|
ORDER BY
|
||||||
orderNum ASC`);
|
orderNum ASC`);
|
||||||
@ -122,7 +123,7 @@ export class BaseSysMenuService extends BaseService {
|
|||||||
* @param menuId
|
* @param menuId
|
||||||
*/
|
*/
|
||||||
async refreshPerms(menuId) {
|
async refreshPerms(menuId) {
|
||||||
const users = await this.nativeQuery('select b.userId from sys_role_menu a left join sys_user_role b on a.roleId = b.roleId where a.menuId = ? group by b.userId', [menuId]);
|
const users = await this.nativeQuery('select b.userId from base_sys_role_menu a left join base_sys_user_role b on a.roleId = b.roleId where a.menuId = ? group by b.userId', [menuId]);
|
||||||
// 刷新admin权限
|
// 刷新admin权限
|
||||||
await this.ctx.service.sys.perms.refreshPerms(1);
|
await this.ctx.service.sys.perms.refreshPerms(1);
|
||||||
if (!_.isEmpty(users)) {
|
if (!_.isEmpty(users)) {
|
||||||
|
|||||||
62
src/app/modules/base/service/sys/perms.ts
Normal file
62
src/app/modules/base/service/sys/perms.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { Inject, Provide } from '@midwayjs/decorator';
|
||||||
|
import { BaseService, CoolCache } from 'midwayjs-cool-core';
|
||||||
|
import { BaseSysMenuService } from './menu';
|
||||||
|
import { BaseSysRoleService } from './role';
|
||||||
|
import { BaseSysDepartmentService } from './department';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
export class BaseSysPermsService extends BaseService {
|
||||||
|
|
||||||
|
@Inject('cool:cache')
|
||||||
|
coolCache: CoolCache;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysMenuService: BaseSysMenuService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysRoleService: BaseSysRoleService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysDepartmentService: BaseSysDepartmentService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新权限
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
async refreshPerms(userId) {
|
||||||
|
const roleIds = await this.baseSysRoleService.getByUser(userId);
|
||||||
|
const perms = await this.ctx.service.sys.menu.getPerms(roleIds);
|
||||||
|
await this.coolCache.set(`admin:perms:${userId}`, JSON.stringify(perms), this.app.config.token.expires);
|
||||||
|
// 更新部门权限
|
||||||
|
const departments = await this.baseSysDepartmentService.getByRoleIds(roleIds, this.ctx.admin.username === 'admin');
|
||||||
|
await this.coolCache.set(`admin:department:${userId}`, JSON.stringify(departments), this.app.config.token.expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得权限菜单
|
||||||
|
* @param roleIds
|
||||||
|
*/
|
||||||
|
async permmenu(roleIds: number[]) {
|
||||||
|
const perms = await this.baseSysMenuService.getPerms(roleIds);
|
||||||
|
const menus = await this.baseSysMenuService.getMenus(roleIds, this.ctx.admin.username === 'admin');
|
||||||
|
return { perms, menus };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID获得部门权限
|
||||||
|
* @param userId
|
||||||
|
* @return 部门ID数组
|
||||||
|
*/
|
||||||
|
async departmentIds(userId: number) {
|
||||||
|
const department = await this.coolCache.get(`admin:department:${userId}`);
|
||||||
|
if (department) {
|
||||||
|
return JSON.parse(department);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,8 +25,10 @@ export class BaseSysUserService extends BaseService {
|
|||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
async test(){
|
/**
|
||||||
// const a = await this.adminSysUserEntity.find();
|
* 获得个人信息
|
||||||
// console.log(a);
|
*/
|
||||||
|
async person() {
|
||||||
|
return await this.baseSysUserEntity.findOne({ id: this.ctx.admin.userId })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,6 +53,8 @@ export default (appInfo: EggAppInfo) => {
|
|||||||
router: {
|
router: {
|
||||||
prefix: ''
|
prefix: ''
|
||||||
},
|
},
|
||||||
|
// 单点登录
|
||||||
|
sso: false,
|
||||||
// jwt 生成解密token的
|
// jwt 生成解密token的
|
||||||
jwt: {
|
jwt: {
|
||||||
// 注意: 最好重新修改,防止破解
|
// 注意: 最好重新修改,防止破解
|
||||||
|
|||||||
@ -7,10 +7,10 @@ export default (appInfo: EggAppInfo) => {
|
|||||||
|
|
||||||
config.orm = {
|
config.orm = {
|
||||||
type: 'mysql',
|
type: 'mysql',
|
||||||
host: '127.0.0.1',
|
host: '139.196.196.203',
|
||||||
port: 3306,
|
port: 3306,
|
||||||
username: 'root',
|
username: 'cool-admin-next',
|
||||||
password: '123123',
|
password: 'Rr4bktexbMNTPmyJ',
|
||||||
database: 'cool-admin-next',
|
database: 'cool-admin-next',
|
||||||
// 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失
|
// 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失
|
||||||
synchronize: true,
|
synchronize: true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user