ld-egg-frame
v2.1.11
Published
#### 端信息校验(auth/webAuth) 主要功能:登录用户身份信息校验 说明:依据client头字段进行不同端的校验,框架提供默认的`web=>app/middleware/webAuth.js`中间件,用户可以自定义其他端的中间件校验。 如果配置了接口权限校验,会根据用户信息进行接口权限校验。
Downloads
14
Readme
框架说明
端信息校验(auth/webAuth)
主要功能:登录用户身份信息校验
说明:依据client头字段进行不同端的校验,框架提供默认的`web=>app/middleware/webAuth.js`中间件,用户可以自定义其他端的中间件校验。
如果配置了接口权限校验,会根据用户信息进行接口权限校验。
// 自定义端信息校验案例(例如weapp中间校验)
// 新建中间件 app/middleware/weappAuth.js
module.exports = (opts, app) => {
return async function weapp(ctx, next) {
// 常用的写法
if (ctx.request.header.client !== 'weapp') return await next();
const jwtDecoded = ctx.getJwtDecoded();
// TODO 业务处理
ctx.weappUser = await app.getModel('weappUser').findById(jwtDecoded.userId);
await next();
};
};
// 配置 app/config/config.default.js, 新增配置
expotrs.middleware = [ 'weappAuth' ]
exports.weappAuth = {
... // 自定义需要的配置
}
配置
jwt配置
// 其他配置详见egg-jwt
{
enable: true,
access: ['GET /abc/cba'] // 配置jwt白名单,这里配置接口同时会跳过webAuth的校验
}
auth配置
// 如果关闭后,仅校验头部带client的接口,其他接口不做校验,默认开启
{ enable: true }
webAuth配置
{
enable: true,
interfaceEnable: true, // 是否开启接口校验
// 通用接口,不进行接口校验,但是有进行token校验
interfaceAccess: [
'GET /user/menu',
'GET /common/uptoken',
'GET /common/upsetting',
'GET /user/info',
],
}
安全配置(跨域)
exports.security = {
origin: '',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
csrf: { enable: false },
domainWhiteList: [ 'http://localhost:9527' ],
};
基于mongoose封装的快捷方法
// 查看某个值最大值的对象
async max(field, filter = {}) {
const res = await this.findOne(filter).sort({ [field]: -1 });
return res;
},
// 查看某个值最小值的对象
async min(field, filter = {}) {
const res = await this.findOne(filter).sort({ [field]: 1 });
return res;
},
// 查看某个值的最小值
async minField(field, filter = {}) {
const res = await this.findOne(filter, field).sort({ [field]: 1 });
return res ? res._doc[field] : void 0;
},
// 查看某个值的最大值
async maxField(field, filter = {}) {
const res = await this.findOne(filter, field).sort({ [field]: -1 });
return res ? res._doc[field] : void 0;
},
// 查找符合条件的id
async findIds(filter = {}) {
const docs = await this.find(filter, '_id');
return docs.map(e => e.id);
},
// 查找符合条件的字段
async findFields(filter = {}, key) {
const docs = await this.find(filter, key);
return docs.map(e => e[key]);
},
// 符合查询条件的内容是否存在
async exist(filter) {
const q = await this.countDocuments(filter);
return q > 0;
},
// 查看id数组的数据是否全部
async idsExist(ids) {
const q = await this.countDocuments({ _id: { $in: ids } });
return q === ids.length;
},
// 递增
async inc(filter, doc) {
if (isObjectId) filter = { _id: filter };
return await this.update(filter, { $inc: doc });
},
// 列表查询
async list(filter, page = 1, perPage = 10, select = null, opts = {}) {
page = Number(page || 1);
perPage = Number(perPage || 10);
const skip = perPage * (page - 1);
const sort = opts.sort || { createdAt: -1 };
const list = await this.find(filter, select, _.omit(opts, [ 'sort' ])).skip(skip).limit(perPage)
.sort(sort);
const total = await this.countDocuments(filter);
return {
list,
pagination: {
perPage,
page,
total,
},
};
},
async getOne(filter, select = null, opts = {}) {
if (isObjectId) filter = { _id: filter };
const doc = await this.findOne(filter, select, opts);
if (!doc) throw Error('getOne:未找到文档');
return doc;
},
async update(id, data) {
const doc = await this.findById(id);
if (!doc) throw Error('update:未找到文档');
Object.keys(data).forEach(k => { doc.set(k, data[k]); });
doc.save();
return doc;
},
async upsert(condition, data, opts = {}) {
opts = Object.assign({ upsert: true, new: true }, opts);
const old = await this.findOne(condition);
if (!old) Object.assign(data, opts.initData || {});
return await this.findOneAndUpdate(condition, data, opts);
},
async delete(id) {
const doc = await this.findById(id);
if (!doc) throw Error('delete:未找到文档');
doc.remove();
return doc;
},
框架默认
默认表
user表
// 校验规则
exports.fields = {
account: 'required|string',
password: 'required|password',
name: 'string',
phoneNumber: 'mobile',
roleIds: 'required|array',
creatorId: 'objectId',
};
exports.update = {
enable: [ 'name', 'roleIds', 'phoneNumber' ],
privacy: [ 'password' ],
};
exports.fetch = {
privacy: [ 'password' ],
};
exports.fetchAll = exports.fetchList = {
input: {
roleId: 'objectId',
},
search: [ 'account' ],
privacy: [ 'password' ],
async beforeHook() {
const { ctx } = this;
const roleId = ctx.input.roleId;
if (roleId) {
ctx.addFilter({
roleIds: roleId,
});
}
},
};
exports.destory = {
privacy: [ 'password' ],
async beforeHook() {
const { ctx, app } = this;
const operator = ctx.user;
const delUser = await app.getModel('user').findById(ctx.params._id);
if (delUser.account === 'super') ctx.throwBizError('超管用户不允许删除');
if (operator.account !== 'super') ctx.throwBizError('仅允许超管删除用户');
},
};
exports.autoRestful = true;
exports.zhName = '用户';
exports.support = [ 'update', 'fetchList', 'fetch', 'fetchAll', 'destory' ];
role表
exports.fields = {
name: 'required|string',
mark: 'string',
menuIds: 'array',
interfaceIds: 'array',
permissions: 'required|array',
};
exports.create = {
unique: [ 'name' ],
default: { permissions: [] },
};
exports.update = {
unique: [ 'name' ],
};
exports.fetchList = {
search: [ 'name', 'mark' ],
};
exports.destory = {
async afterHook(entity) {
const { app } = this;
await app.getModel('user').updateMany({ roleIds: entity.id }, { $pull: { roleIds: entity.id } });
},
};
exports.zhName = '角色';
exports.autoRestful = true;
menu表
exports.fields = {
path: 'required|string',
component: 'required|string',
name: 'required|string',
meta: 'required|object',
hide: 'boolean',
alwaysShow: 'boolean',
parentId: 'objectId',
type: 'required|string|in:root,sub',
interfaceIds: 'required|array',
};
exports.update = exports.create = {
unique: [ 'name' ],
async beforeHook() {
const { ctx, app } = this;
const input = ctx.input;
if (input.type === 'sub' && !input.parentId) ctx.throwBizError('子菜单必须传父菜单Id');
if (input.parentId) {
const parentExist = await app.getModel('menu').qk.exist({ _id: input.parentId });
if (!parentExist) ctx.throwBizError('父级菜单不存在');
}
const interfaceExist = await app.getModel('interface').qk.idsExist(input.interfaceIds);
if (!interfaceExist) ctx.throwBizError('存在未知接口');
},
};
exports.autoRestful = true;
exports.zhName = '菜单';
exports.support = [ 'create', 'update', 'fetch', 'destory' ];
interface表
exports.fields = {
name: 'string',
alias: 'string',
path: 'required|string',
mark: 'required|string',
method: 'required|string',
state: 'required|string',
access: 'required|boolean',
};
exports.fetchAll = exports.fetchList = {
search: [ 'name', 'mark' ],
input: {
access: 'boolean',
state: 'string',
},
match: [ 'state', 'access' ],
};
exports.autoRestful = true;
exports.zhName = '接口';
exports.support = [ 'fetchAll', 'fetchList' ];
默认控制器
- controller/common.js
- controller/permission.js
- controller/user.js
- controller/web.js
默认服务
- service/user.js
- service/role.js
- service/menu.js
- service/interface.js
默认中间件
- middleware/errorHandler.js
- middleware/jwt.js
默认路由
// 权限配置
router.put('刷新接口信息', '/sys/permission/interface', controller.permission.refreshInterface);
router.put('更新白名单接口', '/sys/permission/interface/access', controller.permission.updateAccessInterface);
router.put('绑定角色', '/user/role', controller.permission.bindRole);
router.put('配置角色权限', '/role/permission', controller.permission.setRolePermission);
router.get('获取菜单树', '/menu/tree', controller.permission.getMenuTree);
router.get('获取用户菜单树', '/user/menu', controller.permission.getUserMenu);
router.get('获取用户信息', '/user/info', controller.user.getInfo);
router.post('添加用户', '/user', controller.user.addUser);
// 后台 登录注册
router.post('后台登录', '/web/login', controller.web.login);
router.post('后台注册', '/web/register', controller.web.register);
// 资源上传
router.get('获取OSS上传token', '/common/uptoken', controller.common.uptoken);
router.get('获取OSS配置', '/common/upsetting', controller.common.uploadSetting);
// 权限配置
router.put('刷新接口信息', '/sys/permission/interface', controller.permission.refreshInterface);
router.put('更新白名单接口', '/sys/permission/interface/access', controller.permission.updateAccessInterface);
router.put('绑定角色', '/user/role', controller.permission.bindRole);
router.put('配置角色权限', '/role/permission', controller.permission.setRolePermission);
router.get('获取菜单树', '/menu/tree', controller.permission.getMenuTree);
router.get('获取用户菜单树', '/user/menu', controller.permission.getUserMenu);
router.get('获取用户信息', '/user/info', controller.user.getInfo);
router.post('添加用户', '/user', controller.user.addUser);
// 后台 登录注册
router.post('后台登录', '/web/login', controller.web.login);
router.post('后台注册', '/web/register', controller.web.register);
// 资源上传
router.get('获取OSS上传token', '/common/uptoken', controller.common.uptoken);
router.get('获取OSS配置', '/common/upsetting', controller.common.uploadSetting);
备忘
- 中间件的顺序:coreMiddleware > 插件中间件 > 应用中间件