From 046940e2e8cbddc14e39aa6519f78c209650e9b6 Mon Sep 17 00:00:00 2001 From: ap <951984189@qq.com> Date: Wed, 24 Feb 2021 23:34:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/middleware.code-snippets | 5 +- src/app/extend/helper.ts | 33 +++--- src/app/{resource => extend}/ipipfree.ipdb | Bin src/app/modules/base/config.ts | 2 +- src/app/modules/base/controller/admin/comm.ts | 32 +++--- src/app/modules/base/controller/admin/open.ts | 40 +++++++ .../base/controller/admin/sys/department.ts | 29 +++++ .../modules/base/controller/admin/sys/menu.ts | 20 ++++ src/app/modules/base/entity/sys/log.ts | 4 + src/app/modules/base/middleware/authority.ts | 105 ++++++++++++++++++ src/app/modules/base/middleware/log.ts | 20 ++-- .../modules/base/service/sys/department.ts | 67 ++++++++++- src/app/modules/base/service/sys/log.ts | 28 +++-- src/app/modules/base/service/sys/login.ts | 54 ++++++--- src/app/modules/base/service/sys/menu.ts | 15 +-- src/app/modules/base/service/sys/perms.ts | 62 +++++++++++ src/app/modules/base/service/sys/user.ts | 8 +- src/config/config.default.ts | 2 + src/config/config.local.ts | 6 +- 19 files changed, 450 insertions(+), 82 deletions(-) rename src/app/{resource => extend}/ipipfree.ipdb (100%) create mode 100644 src/app/modules/base/controller/admin/open.ts create mode 100644 src/app/modules/base/controller/admin/sys/department.ts create mode 100644 src/app/modules/base/controller/admin/sys/menu.ts create mode 100644 src/app/modules/base/middleware/authority.ts create mode 100644 src/app/modules/base/service/sys/perms.ts diff --git a/.vscode/middleware.code-snippets b/.vscode/middleware.code-snippets index 723ba1b..b0a2d93 100644 --- a/.vscode/middleware.code-snippets +++ b/.vscode/middleware.code-snippets @@ -3,7 +3,8 @@ "prefix": "middleware", "body": [ "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 {", "", " resolve() {", - " return async (ctx: IMidwayWebContext, next: IMidwayWebNext) => {", + " return async (ctx: Context, next: IMidwayWebNext) => {", " // 控制器前执行的逻辑", " const startTime = Date.now();", " // 执行下一个 Web 中间件,最后执行到控制器", diff --git a/src/app/extend/helper.ts b/src/app/extend/helper.ts index 57d28c6..b6027a6 100644 --- a/src/app/extend/helper.ts +++ b/src/app/extend/helper.ts @@ -1,32 +1,31 @@ +import { Provide } from '@midwayjs/decorator'; import * as ipdb from 'ipip-ipdb'; import * as _ from 'lodash'; +import { Context } from 'egg'; /** * 帮助类 */ -export default class Helper { - /** - * 获得请求IP - */ - public static async getReqIP() { - // @ts-ignore - const req = this.ctx.req; - return (req.headers['x-forwarded-for'] || // 判断是否有反向代理 IP - req.connection.remoteAddress || // 判断 connection 的远程 IP - req.socket.remoteAddress || // 判断后端的 socket 的 IP - req.connection.socket.remoteAddress).replace('::ffff:', ''); +@Provide() + export class Helper { + /** + * 获得请求IP + */ + public async getReqIP(ctx: Context) { + const req = ctx.req; + return req.headers['x-forwarded-for'] || req.socket.remoteAddress } /** * 根据IP获得请求地址 * @param ip 为空时则为当前请求的IP地址 */ - public static async getIpAddr(ip?: string) { + public async getIpAddr(ctx: Context, ip?: string | string[]) { try { 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 addArr: any = []; if (result) { @@ -35,7 +34,7 @@ export default class Helper { addArr.push(result.cityName); return _.uniq(addArr).join(''); } - // @ts-ignore + // @ts-ignore } catch (err) { return '无法获取地址信息'; } @@ -45,7 +44,7 @@ export default class Helper { * 去除对象的空值属性 * @param obj */ - public static async removeEmptyP (obj) { + public async removeEmptyP(obj) { Object.keys(obj).forEach(key => { if (obj[key] === null || obj[key] === '' || obj[key] === 'undefined') { delete obj[key]; @@ -57,7 +56,7 @@ export default class Helper { * 线程阻塞毫秒数 * @param ms */ - public static sleep(ms) { + public sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } diff --git a/src/app/resource/ipipfree.ipdb b/src/app/extend/ipipfree.ipdb similarity index 100% rename from src/app/resource/ipipfree.ipdb rename to src/app/extend/ipipfree.ipdb diff --git a/src/app/modules/base/config.ts b/src/app/modules/base/config.ts index ea9a76f..465ece3 100644 --- a/src/app/modules/base/config.ts +++ b/src/app/modules/base/config.ts @@ -11,6 +11,6 @@ export default (app: Application) => { // 模块描述 describe: '基础的权限管理功能,包括登录,权限校验', // 中间件 - middlewares: ['baseLogsMiddleware'], + middlewares: ['baseLogMiddleware', 'baseAuthorityMiddleware'], } as ModuleConfig; }; diff --git a/src/app/modules/base/controller/admin/comm.ts b/src/app/modules/base/controller/admin/comm.ts index 68e5c84..3275c7f 100644 --- a/src/app/modules/base/controller/admin/comm.ts +++ b/src/app/modules/base/controller/admin/comm.ts @@ -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 { LoginDTO } from '../../dto/login'; -import { BaseSysLoginService } from '../../service/sys/login'; +import { BaseSysPermsService } from '../../service/sys/perms'; +import { BaseSysUserService } from '../../service/sys/user'; /** * Base 通用接口 一般写不需要权限过滤的接口 @@ -11,23 +12,28 @@ import { BaseSysLoginService } from '../../service/sys/login'; export class BaseCommController extends BaseController { @Inject() - baseSysLoginService: BaseSysLoginService; + baseSysUserService: BaseSysUserService; + + @Inject() + baseSysPermsService: BaseSysPermsService; + + @Inject() + ctx: Context; /** - * 登录 - * @param login + * 获得个人信息 */ - @Post('/login') - async login(@Body(ALL) login: LoginDTO) { - return this.ok(await this.baseSysLoginService.login(login)) + @Get('/person') + public async person() { + return this.ok(await this.baseSysUserService.person()); } /** - * 获得验证码 + * 权限菜单 */ - @Get('/captcha') - async captcha(@Query() type: string, @Query() width: number, @Query() height: number) { - return this.ok(await this.baseSysLoginService.captcha(type, width, height)); + @Get('/permmenu') + public async permmenu() { + return this.ok(await this.baseSysPermsService.permmenu(this.ctx.admin.roleIds)); } } \ No newline at end of file diff --git a/src/app/modules/base/controller/admin/open.ts b/src/app/modules/base/controller/admin/open.ts new file mode 100644 index 0000000..987aa74 --- /dev/null +++ b/src/app/modules/base/controller/admin/open.ts @@ -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)) + } +} \ No newline at end of file diff --git a/src/app/modules/base/controller/admin/sys/department.ts b/src/app/modules/base/controller/admin/sys/department.ts new file mode 100644 index 0000000..65ff5d5 --- /dev/null +++ b/src/app/modules/base/controller/admin/sys/department.ts @@ -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(); + } + +} \ No newline at end of file diff --git a/src/app/modules/base/controller/admin/sys/menu.ts b/src/app/modules/base/controller/admin/sys/menu.ts new file mode 100644 index 0000000..a7e4ccb --- /dev/null +++ b/src/app/modules/base/controller/admin/sys/menu.ts @@ -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; + +} \ No newline at end of file diff --git a/src/app/modules/base/entity/sys/log.ts b/src/app/modules/base/entity/sys/log.ts index bd4f675..3108c2b 100644 --- a/src/app/modules/base/entity/sys/log.ts +++ b/src/app/modules/base/entity/sys/log.ts @@ -26,4 +26,8 @@ export class BaseSysLogEntity extends BaseEntity { @Column({ comment: '参数', nullable: true, type: 'text' }) params: string; + + @Column({ comment: '响应毫秒数, 值为-1则响应不成功', default: -1 }) + ms: number; + } diff --git a/src/app/modules/base/middleware/authority.ts b/src/app/modules/base/middleware/authority.ts new file mode 100644 index 0000000..b3e4664 --- /dev/null +++ b/src/app/modules/base/middleware/authority.ts @@ -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(); + }; + } + +} \ No newline at end of file diff --git a/src/app/modules/base/middleware/log.ts b/src/app/modules/base/middleware/log.ts index bad3b35..92f8ea2 100644 --- a/src/app/modules/base/middleware/log.ts +++ b/src/app/modules/base/middleware/log.ts @@ -1,21 +1,21 @@ -import { Provide } from '@midwayjs/decorator'; -import { IWebMiddleware, IMidwayWebNext, IMidwayWebContext } from '@midwayjs/web'; +import { Inject, Provide } from '@midwayjs/decorator'; +import { IWebMiddleware, IMidwayWebNext } from '@midwayjs/web'; +import { BaseSysLogService } from '../service/sys/log'; +import { Context } from 'egg'; /** * 日志中间件 */ @Provide() -export class BaseLogsMiddleware implements IWebMiddleware { +export class BaseLogMiddleware implements IWebMiddleware { + + @Inject() + baseSysLogService: BaseSysLogService; resolve() { - return async (ctx: IMidwayWebContext, next: IMidwayWebNext) => { - console.log('日志') - // 控制器前执行的逻辑 - const startTime = Date.now(); - // 执行下一个 Web 中间件,最后执行到控制器 + return async (ctx: Context, next: IMidwayWebNext) => { + this.baseSysLogService.record(ctx.url.split('?')[0], ctx.req.method === 'GET' ? ctx.request.query : ctx.request.body, ctx.admin ? ctx.admin.userId : null); await next(); - // 控制器之后执行的逻辑 - console.log(Date.now() - startTime); }; } diff --git a/src/app/modules/base/service/sys/department.ts b/src/app/modules/base/service/sys/department.ts index cafb46f..ceca1b0 100644 --- a/src/app/modules/base/service/sys/department.ts +++ b/src/app/modules/base/service/sys/department.ts @@ -1,10 +1,12 @@ -import { Provide } from '@midwayjs/decorator'; +import { Inject, Provide } from '@midwayjs/decorator'; import { BaseService } from 'midwayjs-cool-core'; import { InjectEntityModel } from '@midwayjs/orm'; import { Repository } from 'typeorm'; import { BaseSysDepartmentEntity } from '../../entity/sys/department'; import * as _ from 'lodash'; 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) baseSysRoleDepartmentEntity: Repository; + @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获得部门权限信息 * @param {[]} roleIds 数组 @@ -40,4 +78,31 @@ export class BaseSysDepartmentService extends BaseService { } 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 ]); + } + } + } + } \ No newline at end of file diff --git a/src/app/modules/base/service/sys/log.ts b/src/app/modules/base/service/sys/log.ts index c412ee3..5999c93 100644 --- a/src/app/modules/base/service/sys/log.ts +++ b/src/app/modules/base/service/sys/log.ts @@ -6,6 +6,7 @@ import { Context } from 'egg'; import * as _ from 'lodash'; import { BaseSysLogEntity } from '../../entity/sys/log'; import * as moment from 'moment'; +import { Helper } from '../../../../extend/helper'; /** * 描述 @@ -16,6 +17,9 @@ export class BaseSysLogService extends BaseService { @Inject() ctx: Context; + // @Inject() + // helper: Helper; + @InjectEntityModel(BaseSysLogEntity) baseSysLogEntity: Repository; @@ -26,18 +30,18 @@ export class BaseSysLogService extends BaseService { * @param userId 用户ID */ async record(url, params, userId) { - const ip = await this.ctx.helper.getReqIP(); - const sysLog = new BaseSysLogEntity(); - sysLog.userId = userId; - sysLog.ip = ip; - const ipAddrArr = new Array(); - for (const e of ip.split(',')) ipAddrArr.push(await this.ctx.helper.getIpAddr(e)); - sysLog.ipAddr = ipAddrArr.join(','); - sysLog.action = url; - if (!_.isEmpty(params)) { - sysLog.params = JSON.stringify(params); - } - await this.baseSysLogEntity.insert(sysLog); + // const ip = await this.helper.getReqIP(this.ctx); + // const sysLog = new BaseSysLogEntity(); + // sysLog.userId = userId; + // sysLog.ip = ip; + // const ipAddrArr = new Array(); + // for (const e of ip.split(',')) ipAddrArr.push(await this.ctx.helper.getIpAddr(e)); + // sysLog.ipAddr = ipAddrArr.join(','); + // sysLog.action = url; + // if (!_.isEmpty(params)) { + // sysLog.params = JSON.stringify(params); + // } + // await this.baseSysLogEntity.insert(sysLog); } /** diff --git a/src/app/modules/base/service/sys/login.ts b/src/app/modules/base/service/sys/login.ts index 9e1c753..14a43d2 100644 --- a/src/app/modules/base/service/sys/login.ts +++ b/src/app/modules/base/service/sys/login.ts @@ -1,5 +1,5 @@ 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 * as svgCaptcha from 'svg-captcha'; import * as svgToDataURL from 'svg-to-dataurl'; @@ -13,6 +13,7 @@ import * as _ from 'lodash'; import { BaseSysMenuService } from './menu'; import { BaseSysDepartmentService } from './department'; import * as jwt from 'jsonwebtoken'; +import { Context } from 'egg'; /** * 登录 @@ -24,7 +25,7 @@ export class BaseSysLoginService extends BaseService { coolCache: CoolCache; @InjectEntityModel(BaseSysUserEntity) - baseSysLogEntity: Repository; + baseSysUserEntity: Repository; @Inject() baseSysRoleService: BaseSysRoleService; @@ -35,8 +36,11 @@ export class BaseSysLoginService extends BaseService { @Inject() baseSysDepartmentService: BaseSysDepartmentService; + @Inject() + ctx: Context; + @Config('cool') - coolConfig; + coolConfig: CoolConfig; /** * 登录 @@ -46,7 +50,7 @@ export class BaseSysLoginService extends BaseService { const { username, captchaId, verifyCode, password } = login; const checkV = await this.captchaCheck(captchaId, verifyCode); if (checkV) { - const user = await this.baseSysLogEntity.findOne({ username }); + const user = await this.baseSysUserEntity.findOne({ username }); if (user) { if (user.status === 0 || user.password !== md5(password)) { throw new CoolCommException('账户或密码不正确~'); @@ -59,12 +63,12 @@ export class BaseSysLoginService extends BaseService { throw new CoolCommException('该用户未设置任何角色,无法登录~'); } - const { expire, refreshExpire } = this.coolConfig.token.jwt; + const { expire, refreshExpire } = this.coolConfig.jwt.token; const result = { expire, token: await this.generateToken(user, roleIds, expire), refreshExpire, - refreshToken: await this.generateToken(user, roleIds, refreshExpire), + refreshToken: await this.generateToken(user, roleIds, refreshExpire, true), }; const perms = await this.baseSysMenuService.getPerms(roleIds); @@ -111,11 +115,11 @@ export class BaseSysLoginService extends BaseService { } /** - * 检验图片验证码 - * @param captchaId 验证码ID - * @param value 验证码 - */ - public async captchaCheck(captchaId, value) { + * 检验图片验证码 + * @param captchaId 验证码ID + * @param value 验证码 + */ + async captchaCheck(captchaId, value) { const rv = await this.coolCache.get(`verify:img:${captchaId}`); if (!rv || !value || value.toLowerCase() !== rv) { return false; @@ -137,16 +141,40 @@ export class BaseSysLoginService extends BaseService { const tokenInfo = { isRefresh: false, roleIds, + username: user.username, userId: user.id, passwordVersion: user.passwordV, }; if (isRefresh) { - delete tokenInfo.roleIds; tokenInfo.isRefresh = true; } return jwt.sign(tokenInfo, - this.coolConfig.token.jwt.secret, { + this.coolConfig.jwt.secret, { 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; + } + + } } \ No newline at end of file diff --git a/src/app/modules/base/service/sys/menu.ts b/src/app/modules/base/service/sys/menu.ts index 68e77dc..f658468 100644 --- a/src/app/modules/base/service/sys/menu.ts +++ b/src/app/modules/base/service/sys/menu.ts @@ -22,7 +22,7 @@ export class BaseSysMenuService extends BaseService { * 获得所有菜单 */ 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)) { menus.forEach(e => { const parentMenu = menus.filter(m => { @@ -46,8 +46,8 @@ export class BaseSysMenuService extends BaseService { let perms = []; if (!_.isEmpty(roleIds)) { const result = await this.nativeQuery(` - SELECT a.perms FROM sys_menu a ${this.setSql(!roleIds.includes('1'), - 'JOIN sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])} + SELECT a.perms FROM base_sys_menu a ${this.setSql(!roleIds.includes('1'), + '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 `, [roleIds]); if (result) { @@ -68,14 +68,15 @@ export class BaseSysMenuService extends BaseService { /** * 获得用户菜单信息 * @param roleIds + * @param isAdmin 是否是超管 */ - async getMenus(roleIds) { + async getMenus(roleIds, isAdmin) { return await this.nativeQuery(` SELECT a.* FROM - sys_menu a - ${this.setSql(!roleIds.includes('1'), 'JOIN sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])} + base_sys_menu a + ${this.setSql(!isAdmin, 'JOIN base_sys_role_menu b on a.id = b.menuId AND b.roleId in (?)', [roleIds])} GROUP BY a.id ORDER BY orderNum ASC`); @@ -122,7 +123,7 @@ export class BaseSysMenuService extends BaseService { * @param 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权限 await this.ctx.service.sys.perms.refreshPerms(1); if (!_.isEmpty(users)) { diff --git a/src/app/modules/base/service/sys/perms.ts b/src/app/modules/base/service/sys/perms.ts new file mode 100644 index 0000000..4718aed --- /dev/null +++ b/src/app/modules/base/service/sys/perms.ts @@ -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 []; + } + } +} \ No newline at end of file diff --git a/src/app/modules/base/service/sys/user.ts b/src/app/modules/base/service/sys/user.ts index 97cc572..87b771d 100644 --- a/src/app/modules/base/service/sys/user.ts +++ b/src/app/modules/base/service/sys/user.ts @@ -25,8 +25,10 @@ export class BaseSysUserService extends BaseService { .execute(); } - async test(){ - // const a = await this.adminSysUserEntity.find(); - // console.log(a); + /** + * 获得个人信息 + */ + async person() { + return await this.baseSysUserEntity.findOne({ id: this.ctx.admin.userId }) } } \ No newline at end of file diff --git a/src/config/config.default.ts b/src/config/config.default.ts index a41c038..e1d48a8 100644 --- a/src/config/config.default.ts +++ b/src/config/config.default.ts @@ -53,6 +53,8 @@ export default (appInfo: EggAppInfo) => { router: { prefix: '' }, + // 单点登录 + sso: false, // jwt 生成解密token的 jwt: { // 注意: 最好重新修改,防止破解 diff --git a/src/config/config.local.ts b/src/config/config.local.ts index 24a4897..2bfabcf 100644 --- a/src/config/config.local.ts +++ b/src/config/config.local.ts @@ -7,10 +7,10 @@ export default (appInfo: EggAppInfo) => { config.orm = { type: 'mysql', - host: '127.0.0.1', + host: '139.196.196.203', port: 3306, - username: 'root', - password: '123123', + username: 'cool-admin-next', + password: 'Rr4bktexbMNTPmyJ', database: 'cool-admin-next', // 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失 synchronize: true,