uaa.mock.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * @Author: helin3
  3. * @Date: 2024-03-27 15:16:08
  4. * @LastEditors: zhanglin3
  5. * @LastEditTime: 2024-09-09 17:38:42
  6. * @Description: UAA相关接口模拟定义
  7. *
  8. * 模拟接口文件路径遵循规范:`/mock/[模块名]/[功能名].mock.js`
  9. * 更详细的文档请参考:https://github.com/pengzhanbo/vite-plugin-mock-dev-server
  10. */
  11. import { createReadStream, readFileSync } from 'node:fs';
  12. import { Base64 } from 'js-base64';
  13. import { defineMock, backend, normalResponse } from '@/../mock/shared/utils.js';
  14. /**
  15. * 模拟生成访问令牌的函数
  16. * @param {Object} body - 包含用户名和密码的对象
  17. * @returns {Object} 返回一个包含访问令牌、刷新令牌等信息的对象,或在认证失败时返回错误信息。
  18. */
  19. const mockAccessToken = (body) => {
  20. let returnObj = {};
  21. const { username, password } = body;
  22. const suffix = new Date().getTime();
  23. // 根据当前时间戳生成模拟的Token和刷新Token
  24. const userInfo = {
  25. userId: 'admin', // 用户编号
  26. userName: 'admin', // 用户名
  27. userCode: 'admin', // 登录名
  28. userAvatar: '', // 用户头像
  29. userEmail: '', // 用户email
  30. userMobilephone: 'admin', // 联系电话
  31. userSex: 'admin', // 性别
  32. // 已授权的机构列表
  33. authOrgs: [
  34. {
  35. code: '500', // 机构编号
  36. name: '宇信集团', // 机构名称
  37. id: '500',
  38. instuCode: '', // 金融机构编号
  39. instuName: '', // 金融机构名称
  40. // 已授权角色列表
  41. roles: [
  42. {
  43. roleCode: '', // 角色编码
  44. roleName: '', // 角色名称
  45. },
  46. ],
  47. // 当前选择机构
  48. currOrg: {
  49. orgCode: '', // 机构编号
  50. orgName: '', // 机构名称
  51. instuCode: '', // 金融机构编号
  52. instuName: '', // 金融机构名称
  53. // 已授权角色列表
  54. roles: [
  55. {
  56. roleCode: '', // 角色编码
  57. roleName: '', // 角色名称
  58. },
  59. ],
  60. },
  61. },
  62. {
  63. code: '5001', // 机构编号
  64. name: '宇信科技', // 机构名称
  65. id: '5001',
  66. instuCode: '', // 金融机构编号
  67. instuName: '', // 金融机构名称
  68. // 已授权角色列表
  69. roles: [
  70. {
  71. roleCode: '', // 角色编码
  72. roleName: '', // 角色名称
  73. },
  74. ],
  75. // 当前选择机构
  76. currOrg: {
  77. orgCode: '', // 机构编号
  78. orgName: '', // 机构名称
  79. instuCode: '', // 金融机构编号
  80. instuName: '', // 金融机构名称
  81. // 已授权角色列表
  82. roles: [
  83. {
  84. roleCode: '', // 角色编码
  85. roleName: '', // 角色名称
  86. },
  87. ],
  88. },
  89. },
  90. ],
  91. org: {
  92. code: '500', // 机构编号
  93. name: '宇信集团', // 机构名称
  94. id: '500',
  95. },
  96. roles: [{ id: '500', name: '宇信集团', code: 'YUSYS' }],
  97. additionals: {
  98. authOrgRoles: [
  99. {
  100. orgCde: '500',
  101. orgName: '宇信集团',
  102. lastUseTime: '2024-07-25 17:55:35',
  103. usrRoleRelId: '6ACEAA02D8DC11EDBFAC005056BD1C9B',
  104. roleId: '7E6B6DD5DABF498C966D483605691E15',
  105. roleName: '决策引擎超级管理员',
  106. orgId: '500',
  107. roleCde: 'shuffle_admin',
  108. },
  109. {
  110. orgCde: '500',
  111. orgName: '宇信集团',
  112. lastUseTime: '2024-07-30 16:14:03',
  113. usrRoleRelId: 'a2fa6f4c28e34de2ab22cf549de41e31',
  114. roleId: 'cc81a8d86f274c81bc680a0bbd27e358',
  115. roleName: '系统管理员角色',
  116. orgId: '500',
  117. roleCde: 'R001',
  118. },
  119. ],
  120. currentOrgRole: {
  121. orgCde: '500',
  122. orgName: '宇信集团',
  123. lastUseTime: '2024-07-30 16:14:03',
  124. usrRoleRelId: 'a2fa6f4c28e34de2ab22cf549de41e31',
  125. roleId: 'cc81a8d86f274c81bc680a0bbd27e358',
  126. roleName: '系统管理员角色',
  127. orgId: '500',
  128. roleCde: 'R001',
  129. },
  130. },
  131. };
  132. const tempReturnObj = {
  133. accessToken: `MOCK-ACCESSTOKEN-${suffix}`,
  134. expiresIn: 3600, // 令牌有效期为3600秒
  135. refreshToken: `MOCK-REFRESHTOKEN-${suffix}`,
  136. // 用户信息,经过Base64加密过后的登录成功的用户信息
  137. userInfo: Base64.encode(JSON.stringify(userInfo)),
  138. };
  139. // grantType-授权类型: password-登录 subject-切换主体
  140. const { grantType, orgCode } = body;
  141. // 根据不同的grantType返回不同的模拟响应
  142. if (grantType === 'password') {
  143. // 验证用户名和密码,根据结果返回不同的对象
  144. if (username !== 'admin') {
  145. // 账号或密码错误时返回的错误信息
  146. returnObj = normalResponse('', 'UAASYS005', '当前用户不存在或登录密码错误');
  147. } else {
  148. const flag = Math.random() < 0.7 ? 1 : 0;
  149. if (flag) {
  150. // 验证成功时返回模拟的Token信息
  151. returnObj = Object.assign(normalResponse(), { data: tempReturnObj });
  152. } else {
  153. // 随机生成错误场景
  154. const codes = [
  155. { code: 'UAASYS001', message: '验证码错误' },
  156. { code: 'UAASYS002', message: '需进行验证码验证' },
  157. {
  158. code: 'UAASYS003',
  159. message: '首次登录,需进行密码修改',
  160. data: {
  161. accessToken: `MOCK-ACCESSTOKEN-${suffix}`,
  162. expiresIn: 3600, // 令牌有效期为3600秒
  163. refreshToken: `MOCK-REFRESHTOKEN-${suffix}`,
  164. },
  165. },
  166. { code: 'UAASYS004', message: '当前用户的状态不正确' },
  167. // { code: 'UAASYS005', message: '当前用户不存在或登录密码错误' },
  168. { code: 'UAASYS006', message: '当前系统处理异常' },
  169. { code: 'UAASYS007', message: '当前客户端认证信息不存在' },
  170. // { code: 'UAASYS008', message: '当前授权模式不存在' },
  171. { code: 'UAASYS009', message: '当前客户端认证信息异常' },
  172. {
  173. code: 'UAASYS010',
  174. message: '当前用户需要进行密码修改',
  175. data: {
  176. accessToken: `MOCK-ACCESSTOKEN-${suffix}`,
  177. expiresIn: 3600, // 令牌有效期为3600秒
  178. refreshToken: `MOCK-REFRESHTOKEN-${suffix}`,
  179. },
  180. },
  181. { code: 'UAASYS011', message: '当前时间不允许登录' },
  182. { code: 'UAASYS012', message: '用户登录密码有效期已过' },
  183. { code: 'UAASYS013', message: '用户达到系统登录人数上限' },
  184. ];
  185. const index = Math.floor(Math.random() * codes.length);
  186. returnObj = normalResponse(codes[index].data || '', codes[index].code, codes[index].message);
  187. }
  188. }
  189. } else if (grantType === 'subject') {
  190. const org = userInfo.authOrgs.filter((item) => {
  191. return item.code === orgCode;
  192. });
  193. tempReturnObj.org = {
  194. id: org.id,
  195. code: org.code,
  196. name: org.name,
  197. };
  198. returnObj = Object.assign(normalResponse(), { data: tempReturnObj });
  199. } else if (grantType === 'refresh') {
  200. returnObj = Object.assign(normalResponse(), { data: tempReturnObj });
  201. } else {
  202. // 对于不支持的grantType返回错误响应
  203. returnObj = normalResponse('', 'UAASYS008', '当前授权模式不存在');
  204. }
  205. return returnObj;
  206. };
  207. /**
  208. * 模拟生成是否展示验证码及验证码base64
  209. *
  210. * @returns {Object} 返回展示验证码标识及验证码base64
  211. */
  212. const mockImageCode = () => {
  213. // 随机模拟是否开启验证码验证机制
  214. const flag = Math.random() < 0.6 ? 1 : 0;
  215. const tempReturnObj = {
  216. imageShowInd: flag,
  217. };
  218. // 模拟获取图片验证码的响应:验证码展示标识为是时,此处为Base64加密后的图片验证码的byte数组信息
  219. if (flag) {
  220. tempReturnObj.imageCode = readFileSync('./mock/oca/data/image-captcha.png').toString('base64');
  221. }
  222. return normalResponse(tempReturnObj);
  223. };
  224. /**
  225. * 定义模拟API集合,用于开发和测试过程中对真实API的模拟。
  226. * @param {Array} mocks - API模拟的配置数组。
  227. * @returns {Object} 返回一个根据传入的mocks配置的模拟API对象。
  228. */
  229. export default defineMock([
  230. {
  231. url: `${backend.uaaService}/oauth/hasImageCode`, // 查询配置是否需要进行验证码
  232. method: 'POST',
  233. enabled: true, // 启用该接口的模拟
  234. body: () => {
  235. // 模拟注销操作的响应,实际上该接口不返回任何信息
  236. return normalResponse('', undefined, '注-真实注销接口没有返回报文信息');
  237. },
  238. },
  239. // {
  240. // url: `${backend.uaaService}/oauth/token`, // OAuth认证服务的token获取接口
  241. // method: 'POST',
  242. // enabled: true, // 启用该接口的模拟
  243. // body: ({ body }) => {
  244. // let response = {};
  245. // const { grantType } = body;
  246. // // 根据不同的grantType返回不同的模拟响应
  247. // if (grantType === 'password') {
  248. // response = mockAccessToken(body); // 模拟使用密码或oca令牌类型的访问令牌获取
  249. // } else if (grantType === 'refresh') {
  250. // response = mockRefreshToken(body); // 模拟使用刷新令牌获取新的访问令牌
  251. // } else {
  252. // // 对于不支持的grantType返回错误响应
  253. // response = normalResponse('', '-1', '/oauth/token mock error.');
  254. // }
  255. // return response;
  256. // },
  257. // },
  258. {
  259. url: `${backend.uaaService}/api/logout`, // 用户注销接口
  260. method: 'POST',
  261. enabled: true, // 启用该接口的模拟
  262. body: () => {
  263. // 模拟注销操作的响应,实际上该接口不返回任何信息
  264. return normalResponse('', undefined, '注-真实注销接口没有返回报文信息');
  265. },
  266. },
  267. {
  268. url: `${backend.uaaService}/api/codeimage/:uuid`,
  269. method: ['GET', 'POST'],
  270. type: 'xxx.png', // 通过传入名称来设置返回的文件类型
  271. enabled: true,
  272. body: () => {
  273. // 模拟获取图片验证码的响应
  274. // 返回一个指向根目录下mock/oca/data/image-captcha.png文件的可读流
  275. return createReadStream('./mock/oca/data/image-captcha.png');
  276. },
  277. },
  278. // 首次验证码获取
  279. {
  280. url: `${backend.uaaService}/api/verification/code/generate`,
  281. method: ['POST'],
  282. enabled: true,
  283. body: () => {
  284. return mockImageCode();
  285. },
  286. },
  287. // 验证码重新获取
  288. {
  289. url: `${backend.uaaService}/api/verification/code/regenerate`,
  290. method: ['POST'],
  291. enabled: true,
  292. body: () => {
  293. return mockImageCode();
  294. },
  295. },
  296. // 登录/登录后主体切换/刷新token
  297. {
  298. url: `${backend.uaaService}/oauth/token`, // OAuth认证服务的token获取接口
  299. method: 'POST',
  300. enabled: true, // 启用该接口的模拟
  301. // delay: 2000, // 设置延迟时间为1000毫秒(即1秒)
  302. body: ({ body }) => {
  303. return mockAccessToken(body);
  304. },
  305. },
  306. ]);