home.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. 'use strict';
  2. const Controller = require('egg').Controller;
  3. const jsonwebtoken = require('jsonwebtoken');
  4. const FormStream = require('formstream');
  5. class HomeController extends Controller {
  6. async index() {
  7. const { modules } = this.app.config;
  8. // 路径参数
  9. const { agent, service, module, method, item } = this.ctx.params;
  10. // 请求地址
  11. const address = modules[service];
  12. // 请求方法
  13. const requestMethod = this.ctx.request.method;
  14. // 请求路径
  15. const path = this.ctx.path;
  16. let msg,
  17. details,
  18. result = null;
  19. // jwt 验证
  20. const auth = await this.auth({ service, path });
  21. // 验证失败
  22. if (auth.errcode !== 0) {
  23. this.ctx.status = 401;
  24. this.ctx.body = { errcode: 401, errmsg: '身份验证失败', details: auth.details };
  25. return false;
  26. }
  27. // 发送的数据
  28. let data = requestMethod === 'GET' ? this.ctx.query : this.ctx.request.body;
  29. if (requestMethod === 'DELETE') data = this.ctx.params.item;
  30. // 参数定义
  31. let form = {};
  32. const options = {
  33. method: requestMethod,
  34. data,
  35. headers: {},
  36. 'Content-Type': 'application/json',
  37. nestedQuerystring: true,
  38. };
  39. if (method !== 'get_verification_code' && method !== 'upload' && method !== 'import') {
  40. options.dataType = 'json';
  41. }
  42. // 如果是文件上传
  43. if (method === 'upload' || method === 'import') {
  44. const stream = await this.ctx.getFileStream();
  45. form = new FormStream();
  46. form.stream(stream.fieldname, stream, stream.filename);
  47. options.stream = form;
  48. options.headers = form.headers();
  49. options['Content-Type'] = 'multipart/form-data';
  50. }
  51. if (method == 'filesDownload') {
  52. delete options.dataType
  53. }
  54. // 发送请求
  55. let res;
  56. try {
  57. res = await this.ctx.curl(`${address}${path}`, options);
  58. // 默认返回值
  59. msg = res.data;
  60. // 日志详情默认值
  61. details = data;
  62. result = '成功';
  63. // 错误异常处理(返回值)
  64. // 缺少字段检测返回asser
  65. if (res.status === 500 && res.data.name === 'AssertionError') {
  66. msg = { errcode: -1002, errmsg: res.data.message, data: '' };
  67. details = res.data.message;
  68. result = '失败';
  69. }
  70. // 异常抛出检测
  71. if (res.status === 500 && (res.data.name === 'ValidationError' || res.data.name === 'CastError')) {
  72. msg = { errcode: -1002, errmsg: '系统错误', details: res.data.message };
  73. details = res.data.message;
  74. result = '失败';
  75. }
  76. } catch (error) {
  77. result = '失败';
  78. details = error;
  79. msg = { errcode: -1002, errmsg: '系统错误', details: error };
  80. console.log(error, 'error');
  81. }
  82. // 写日志
  83. await this.setLog({ agent, service, module, method, item, details: JSON.stringify(details), result, auth });
  84. // 默认返回状态 = 当前请求返回状态
  85. this.ctx.response.type = res.headers['content-type'];
  86. this.ctx.status = res.status;
  87. this.ctx.body = msg;
  88. }
  89. // 日志记录
  90. async setLog({ agent, service, module, method, item, details, result, auth }) {
  91. // 配置
  92. const { modules, apipath } = this.app.config;
  93. // 请求路径
  94. const path = this.ctx.path;
  95. // 根据service类型 获取配置文件
  96. const logmodules = apipath[service];
  97. // 没有配置文件默认放过
  98. if (logmodules) {
  99. const items = await this.rewrite_path(logmodules, path);
  100. if (items && items.log) {
  101. // 此处开始记录日志
  102. let userName = null;
  103. let name = null;
  104. if (auth.decode) {
  105. userName = auth.decode.userName;
  106. name = auth.decode.name;
  107. }
  108. try {
  109. await this.ctx.curl(`${modules.log}/api/log/adminlog/create`, {
  110. method: 'POST',
  111. dataType: 'json',
  112. data: { agent, service, module, method, item, details, result, userName, name },
  113. });
  114. } catch (error) {
  115. this.ctx.logger.error(`日志添加失败: ${error}`);
  116. }
  117. }
  118. }
  119. }
  120. // 验证函数
  121. async auth({ service, path }) {
  122. const { jwt, apipath } = this.app.config;
  123. // 根据service类型 获取配置文件
  124. const modules = apipath[service];
  125. // 没有配置文件默认放过
  126. if (!modules) return { errcode: 0, details: '' };
  127. // 获取与当前路径匹配的项
  128. // const item = modules.filter(e => e.url.includes(path));
  129. const item = await this.rewrite_path(modules, path);
  130. // 没有匹配数据 默认放过 不验证jwt放过
  131. if (!item || !item.jwt) return { errcode: 0, details: '' };
  132. // 获取token
  133. const token = this.ctx.header.authorization;
  134. try {
  135. // 解密jwt
  136. const decode = jsonwebtoken.verify(token, jwt.secret);
  137. // 如果有验证签发者
  138. if (item && item.issuer) {
  139. // 比对签发者
  140. if (!item.issuer.includes(decode.iss)) return { errcode: -4001, details: 'issuer fail verification' };
  141. }
  142. return { errcode: 0, details: '', decode: decode._doc };
  143. } catch (error) {
  144. return { errcode: -4001, details: error.message };
  145. }
  146. }
  147. // 重写路径
  148. async rewrite_path(modules, path) {
  149. return modules.find(e => {
  150. const { url } = e;
  151. let data = null;
  152. const urlList = url.split('/');
  153. const pathIist = path.split('/');
  154. const urlItem = urlList.findIndex(j => j.includes(':'));
  155. if (urlItem > 0) data = pathIist[urlItem];
  156. if (data !== null) urlList[urlItem] = data;
  157. const pathItem = urlList.join('/');
  158. if (pathItem === path) return e;
  159. return false;
  160. });
  161. }
  162. }
  163. module.exports = HomeController;