npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

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 > 插件中间件 > 应用中间件

参考

egg.js官网