Explorar o código

修改查询,匹配分站模式;添加中间件:检查token并转换到ctx.user上;password密码转换

lrf %!s(int64=3) %!d(string=hai) anos
pai
achega
94e425486d
Modificáronse 6 ficheiros con 85 adicións e 6 borrados
  1. 9 2
      README.zh_CN.md
  2. 2 2
      app.js
  3. 42 0
      app/middleware/check-token.js
  4. 14 0
      app/middleware/password.js
  5. 16 1
      lib/service/crud-service.js
  6. 2 1
      package.json

+ 9 - 2
README.zh_CN.md

@@ -1,5 +1,12 @@
-### npm 发布相关
+## 多租户模式
+#### model配置中 
+>```const schema = new Schema(user, { 'multi-tenancy': true, toJSON: { virtuals: true } });```
+
+
+
+
+# npm 发布相关
 
 #### `npm version patch` 更新版本号
 #### `npm publish` 发布
-#### `npm unpublish <包名(@版本)>` 删除指定包的依赖(指定版本)
+#### `npm unpublish <包名(@版本)>` 删除指定包的依赖(指定版本)

+ 2 - 2
app.js

@@ -1,6 +1,6 @@
 'use strict';
 
 module.exports = app => {
-  // 处理请求中抛出的MongoError错误类型,按正常http请求响应业务错误消息
-  app.config.coreMiddleware.unshift('accessLog', 'errorHandler', 'errorMongo');
+  // 处理请求中抛出的MongoError错误类型,按正常http请求响应业务错误消息; 添加检查token并添加用户,password转换,针对非login结尾的路由;
+  app.config.coreMiddleware.unshift('checkToken', 'password', 'accessLog', 'errorHandler', 'errorMongo',);
 };

+ 42 - 0
app/middleware/check-token.js

@@ -0,0 +1,42 @@
+'use strict';
+const _ = require('lodash');
+const jwt = require('jsonwebtoken');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+
+/**
+ * 验证token
+ * @param {Object} token token字符串
+ * @param {String} secret jwt密码
+ */
+const checkJwt = (token, secret) => {
+  if (!token) throw new BusinessError(ErrorCode.ACCESS_DENIED, '缺少秘钥,拒绝访问');
+  const errorList = [
+    { key: 'jwt expired', word: '秘钥已过期,请重新登陆' },
+    { key: 'invalid signature', word: '秘钥错误,请检查秘钥' },
+    { key: 'JSON at position', word: '秘钥错误,请检查秘钥' },
+    { key: 'invalid token', word: '秘钥错误,请检查秘钥' },
+  ];
+  try {
+    const r = jwt.verify(token, secret);
+    if (r) return r; // 如果过期将返回false
+    return false;
+  } catch (e) {
+    const { message } = e;
+    const r = errorList.find(f => message.includes(f.key));
+    if (r) throw new BusinessError(ErrorCode.ACCESS_DENIED, r.word);
+    else throw new BusinessError(ErrorCode.ACCESS_DENIED, '秘钥产生位置错误,检测失败');
+  }
+};
+
+
+module.exports = options => {
+  return async function checkToken(ctx, next) {
+    // token处理
+    const token = _.get(ctx.request, 'header.authorization');
+    if (token) {
+      const r = checkJwt(token, ctx.app.config.jwt.secret);
+      ctx.user = r;
+    }
+    await next();
+  };
+};

+ 14 - 0
app/middleware/password.js

@@ -0,0 +1,14 @@
+'use strict';
+module.exports = options => {
+  return async function password(ctx, next) {
+    // mongodb中secret转换为密码类型
+    const method = ctx.request.method;
+    const isLoginEnd = ctx.request.url.includes('login');
+    const passwordNoDeal = ctx.request.headers.passwordnodeal;
+    if (method !== 'GET' && !isLoginEnd && !passwordNoDeal) {
+      const body = ctx.request.body;
+      if (body && body.password) body.password = { secret: body.password };
+    }
+    await next();
+  };
+};

+ 16 - 1
lib/service/crud-service.js

@@ -50,7 +50,7 @@ class CrudService extends NafService {
     if (sort && isString(sort)) {
       sort = { [sort]: desc ? -1 : 1 };
     } else if (sort && isArray(sort)) {
-      sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
+      sort = sort.map((f) => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
     }
 
     return await this.model.findOne(filter, projection).exec();
@@ -64,7 +64,10 @@ class CrudService extends NafService {
       sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
     }
     let condition = cloneDeep(filter);
+    // 分站模式确认
     condition = this.dealFilter(condition);
+    const _tenant = this.isMultiTenancy();
+    if (_tenant) condition._tenant = _tenant;
     const pipeline = [{ $match: condition }];
     // 先排序
     if (sort) pipeline.push({ $sort: sort });
@@ -83,6 +86,9 @@ class CrudService extends NafService {
   async count(filter) {
     let condition = cloneDeep(filter);
     condition = this.dealFilter(condition);
+    // 分站模式确认
+    const _tenant = this.isMultiTenancy();
+    if (_tenant) condition._tenant = _tenant;
     let count = 0;
     const res = await this.model.aggregate([{ $match: condition }, { $count: 'id' }]);
     if (res && isArray(res)) {
@@ -91,6 +97,15 @@ class CrudService extends NafService {
     }
     return count;
   }
+  /**
+   * 判断默认model是否是分站模式
+   * 是分站模式且不是master,就返回分站标识
+   */
+  isMultiTenancy() {
+    const is_multi = this.model.prototype.schema.options['multi-tenancy'];
+    const tenant = this.model.prototype.schema.options['x-tenant'];
+    if (is_multi && tenant !== 'master') return tenant;
+  }
 
   async queryAndCount(filter, options) {
     filter = this.dealFilter(filter);

+ 2 - 1
package.json

@@ -24,7 +24,8 @@
     "eslint": "^6.5.1",
     "eslint-config-egg": "^7.5.1",
     "eslint-config-naf": "^0.0.6",
-    "webstorm-disable-index": "^1.2.0"
+    "webstorm-disable-index": "^1.2.0",
+    "jsonwebtoken": "^8.5.1"
   },
   "engines": {
     "node": ">=8.9.0"