entry-igwAuth.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. /**
  2. * @Description: 将数据加密后存储到 sessionStorage
  3. * @Params:
  4. * - sessionStorageKey (String): 存储的键名
  5. * - sessionStorageValue (Any): 需要加密存储的值
  6. * @Return: void
  7. */
  8. function setStorageEncryptData(sessionStorageKey, sessionStorageValue) {
  9. if (!sessionStorageKey || sessionStorageValue === undefined) {
  10. console.error("Invalid parameters for setStorageEncryptData");
  11. return;
  12. }
  13. try {
  14. const encryptData = CryptoJS.AES.encrypt(
  15. JSON.stringify(sessionStorageValue),
  16. secretKey
  17. ).toString();
  18. sessionStorage.setItem(sessionStorageKey, encryptData);
  19. } catch (error) {
  20. console.error("Error encrypting data:", error);
  21. }
  22. }
  23. var wx_code = "",
  24. ticket = "", //票据
  25. accessToken = "",
  26. userInfo = {}, //用户信息
  27. AppInfo = {}, //应用参数
  28. deviceInfo = {}, //设备信息
  29. errorCode = null, //错误码
  30. responseText = "", //错误提示
  31. rootDirLocation = ""; //本地文件路劲
  32. // 1. 注册程序,获取设备信息等
  33. /**
  34. * handleReady
  35. * @description wx.config => agentConfig 执行微信授权、注册应用
  36. * @returns {返回类型} 返回描述
  37. * @since 2023年10月11日 15:31:18
  38. */
  39. function handleReady() {
  40. const jsApiList = [
  41. "IPW",
  42. "multiWindows_open",
  43. "multiWindows_close",
  44. "multiWindows_subscribe",
  45. "multiWindows_publish",
  46. "multiWindows_finish",
  47. "chooseImage",
  48. "scanQRCode",
  49. "hideOptionMenu",
  50. "shareWechatMessage",
  51. "shareAppMessage",
  52. "startAutoLBS",
  53. "stopAutoLBS",
  54. "onLocationChange",
  55. "onMenuShareAppMessage",
  56. "onMenuShareWechat",
  57. "previewFile",
  58. "openChatWithMsg",
  59. "ext_Database_Open",
  60. "ext_Database_Exec",
  61. "ext_Database_Query",
  62. "ext_Database_Close",
  63. "ext_ISCP_Init",
  64. "ext_ISCP_ConnectService",
  65. "ext_ISCP_RhConfig",
  66. "ext_ISCP_GetLocalPort",
  67. "ext_ISCP_RhConnectCtrl",
  68. "ext_ISCP_RhConnState",
  69. "ext_ISCP_RhLocalPortCtrl",
  70. "ext_ISCP_Close",
  71. "ext_ISCP_Status",
  72. "ext_screenControl_direction",
  73. "getLocation",
  74. "getZipAppDirectory",
  75. "multiWindows_open",
  76. "ext_DeviceInfo_GetInfo",
  77. "ext_DeviceInfo_version",
  78. "getAuthCode",
  79. "key",
  80. "setFloatWindow", //开启浮窗
  81. "openChatWithMsg", //会话框
  82. "shareAppMessage", //分享
  83. "getZipAppDirectory", //获取h5包路径
  84. "multiWindows_startWidget", //打开应用 2.0
  85. "multiWindows_open", //打开窗口 2.0
  86. 'ext_FileManager_AppList',//获取应用缓存
  87. 'ext_Intent_Dial',//打电话
  88. ]
  89. wx.config({
  90. beta: true, // 调用wx.invoke形式的接口值时,该值必须为true。
  91. debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  92. appId: AppInfo.corpid, // 必填,政务微信的cropID
  93. timestamp: "1608692903", // 必填,生成签名的时间戳
  94. nonceStr: "XKIvykvwOuAeIbl", // 必填,生成签名的随机串
  95. signature: "ad0c077e6b5fbfe0c9e5394703d8262a3bc21fc3", // 必填,签名,见附录1
  96. jsApiList, // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
  97. });
  98. return new Promise((resolve, reject) => {
  99. wx.ready(function () {
  100. console.log("准备:wx.config: ready");
  101. wx.onHistoryBack(function (res) {
  102. return true;
  103. });
  104. wx.invoke(
  105. "agentConfig",
  106. {
  107. agentid: AppInfo.agentid, // 必填,企业应用的agentid
  108. corpid: AppInfo.corpid, // 必填,企业微信的corpid
  109. timestamp: new Date().valueOf() / 1000, // 必填,生成签名的时间戳,int类型, 如
  110. nonceStr: "", // 必填,生成签名的随机串
  111. signature: "", // 必填,签名,见附录5
  112. },
  113. function (res) {
  114. if (res.err_msg != "agentConfig:ok") {
  115. responseText = res.err_msg || "";
  116. return reject(4002);
  117. }
  118. wx.invoke("ext_DeviceInfo_GetInfo", { data: {} }, function (res) {
  119. if (res.err_msg === "ext_DeviceInfo_GetInfo:ok") {
  120. //成功处理
  121. deviceInfo = { ...res };
  122. sessionStorage.setItem("IPW_KEY", "939847C35AFF0A67");
  123. }
  124. });
  125. return resolve();
  126. }
  127. );
  128. window.uexOnload && window.uexOnload(0);
  129. });
  130. });
  131. }
  132. /**
  133. * getAuthCode
  134. * @desc 获取单点登录企业微信code
  135. * try catch 包裹, 如果新单点登录能获取wx_code 则使用新单点登录,否则使用URL参数获取
  136. * @since 2023年09月27日 16:14:50
  137. */
  138. async function getAuthCode(variable) {
  139. try {
  140. // isAndroid()
  141. let code = await getAuthCodeNew();
  142. return code;
  143. } catch (error) {
  144. console.log("单点登录失败,使用URL参数获取", error)
  145. }
  146. let query = window.location.search.substring(1);
  147. let vars = query.split("&");
  148. console.log("单点登录获取code失败,使用微信跳转换取code", vars)
  149. for (let i = 0; i < vars.length; i++) {
  150. var pair = vars[i].split("=");
  151. if (pair[0] == variable) {
  152. return pair[1];
  153. }
  154. }
  155. return "";
  156. }
  157. /**
  158. * 获取i国网的code(授权码) 替换之前getWxCode()需要 重定向页面获取wx_code
  159. */
  160. function getAuthCodeNew() {
  161. return new Promise((resolve, reject) => {
  162. wx.ready(function () {
  163. wx.invoke(
  164. "getAuthCode",
  165. {
  166. response_type: 'code', //固定值
  167. scope: 'snsapi_base' //固定值
  168. },
  169. function (res) {
  170. if (res.err_msg === 'getAuthCode:ok') {
  171. wx_code = res.code;
  172. resolve(res.code)
  173. } else {
  174. reject(res)
  175. }
  176. }
  177. );
  178. });
  179. });
  180. }
  181. function getWxCode() {
  182. let sURL = AppInfo.url_wxcode;
  183. sURL += "appid=" + AppInfo.corpid;
  184. sURL +=
  185. "&redirect_uri=" + encodeURIComponent("zipapp://local.host/index.html");
  186. sURL += "&response_type=code";
  187. sURL += "&scope=SCOPE";
  188. sURL += "&state=STATE";
  189. sURL += "&agentid=" + AppInfo.agentid;
  190. sURL += "#wechat_redirect";
  191. location.href = sURL;
  192. }
  193. /**
  194. * getIscPort
  195. * @desc 建立isc安全链接
  196. * @returns {Promise<String>} 安全链接端口号
  197. * @since 2023年09月27日 16:34:55
  198. */
  199. function getIscPort() {
  200. return new Promise((resolve, reject) => {
  201. wx.invoke(
  202. "ext_ISCP_Init",
  203. {
  204. // 初始化交互安全平台
  205. data: {
  206. iscpIP: AppInfo.iscpIP,
  207. },
  208. },
  209. function (res) {
  210. console.log("=======================建立安全链接", res);
  211. if (res.err_msg === "ext_ISCP_Init:ok") {
  212. var para = {
  213. ip: AppInfo.ip, //安全交互平台互联网ip,从对接方获取
  214. port: AppInfo.iscpPort, //安全交互平台互联网port,从对接方获取
  215. user: AppInfo.user, //当前登录用户id,可写死
  216. appid: AppInfo.appId, //需要向安全交互平台申请
  217. iscpIP: AppInfo.iscpIP, //链路唯一标识,自己生成(建议赋值为AgentID)
  218. };
  219. wx.invoke(
  220. "ext_ISCP_ConnectService",
  221. {
  222. // 建立安全交互平台链接
  223. data: para,
  224. },
  225. function (res) {
  226. if (res.err_msg === "ext_ISCP_ConnectService:ok") {
  227. let _data = {
  228. ip: AppInfo.baseUrlIp,
  229. port: AppInfo.baseUrlPort,
  230. iscpIP: AppInfo.iscpIP,
  231. appid: AppInfo.appId,
  232. };
  233. wx.invoke(
  234. "ext_ISCP_GetLocalPort",
  235. {
  236. // 转换端口
  237. data: _data,
  238. },
  239. function (res) {
  240. // '939847C35AFF0A67'
  241. if (res.err_msg === "ext_ISCP_GetLocalPort:ok") {
  242. AppInfo.result = res.result;
  243. sessionStorage.setItem("IPW_ISCP_PORT", AppInfo.result);
  244. // TyEvent4005.end();
  245. console.log("=======ext_ISCP_GetLocalPort:ok", res);
  246. resolve(res.result);
  247. wx.invoke(
  248. "getZipAppDirectory",
  249. {
  250. type: "APP_ROOT_DIR",
  251. },
  252. function (res) {
  253. console.log("getZipAppDirectory end", res);
  254. if (res.err_msg === "getZipAppDirectory:ok") {
  255. rootDirLocation = res.directory;
  256. sessionStorage.setItem(
  257. "ROOT_DIR_LOCATION",
  258. res.directory
  259. );
  260. } else {
  261. console.log("getZipAppDirectory end 获取本地路径失败:", res)
  262. }
  263. }
  264. );
  265. } else {
  266. responseText = JSON.stringify(res);
  267. reject(40055);
  268. }
  269. }
  270. );
  271. } else {
  272. responseText = JSON.stringify(res);
  273. reject(4004);
  274. }
  275. }
  276. );
  277. } else {
  278. responseText = JSON.stringify(res);
  279. reject(4003);
  280. }
  281. }
  282. );
  283. })
  284. }
  285. /**
  286. * getIscPortBefore
  287. * @desc 建立isc安全链接2
  288. * @returns {Promise<String>} 安全链接端口号2
  289. * @since 2025年29月27日 16:34:55
  290. */
  291. function getIscPortBefore() {
  292. // 打印当前应用参数
  293. console.log("开始建立安全链接AppInfo:", AppInfo);
  294. // 1. 获取 acl_id_list,优先取 AppInfo.aclIdList,否则默认 [1]
  295. const aclIdList = AppInfo.aclIdList || [1];
  296. // 2. 获取 appId,agentid,iscpIP,iscpPort,ip,sport
  297. const appId = AppInfo.appId || "ipw";
  298. const agentid = AppInfo.agentid;
  299. const iscpIP = AppInfo.iscpIP;
  300. const iscpPort = AppInfo.iscpPort;
  301. const ip = AppInfo.ip;
  302. const sport = AppInfo.iscpPort;
  303. // 3. 组装 businessServiceInfoList,每个 acl_id 对应一个 businessInfo
  304. const businessServiceInfoList = aclIdList.map(acl_id => ({
  305. gateway_id: agentid, // 微应用唯一标识
  306. acl_id, // 业务交互的id
  307. businessInfo: {
  308. sip: AppInfo.baseUrlIp, // 业务交互的ip 填 222.212.254.69?
  309. sport: AppInfo.baseUrlPort // 业务交互端口 填 20016?
  310. }
  311. }));
  312. // 4. 组装 gatewayServiceInfoList,包含所有 acl_id
  313. const gatewayServiceInfoList = [
  314. {
  315. gatewayInfo: {
  316. ip: AppInfo.ip, // 安全接入网关ip地址 填: 222.212.254.69?
  317. port: AppInfo.iscpPort, // 安全接入网关端口 填 20016?
  318. resource: {
  319. acl_id_list: aclIdList, // 业务id集合 填 [1]?
  320. appId: appId // 资源名 填 "ipw"?
  321. },
  322. type: 2 // 固定值 填2?
  323. // sslProfile 可选,后面动态添加
  324. },
  325. gateway_id: agentid // 微应用唯一标识 填 "ipw"?
  326. }
  327. ];
  328. // 5. 如果 AppInfo.sslProfile 存在,添加到 gatewayInfo
  329. if (AppInfo.sslProfile) {
  330. gatewayServiceInfoList[0].gatewayInfo.sslProfile = AppInfo.sslProfile;
  331. }
  332. let dataParsms = {
  333. businessServiceInfoList: businessServiceInfoList, // 业务交互配置
  334. gatewayServiceInfoList: gatewayServiceInfoList // 网关配置
  335. }
  336. console.log("组装好的参数 dataParsms:", dataParsms);
  337. // 6. 调用微信接口建立安全链接
  338. return new Promise((resolve, reject) => {
  339. wx.invoke(
  340. "ext_ISCP_RhConfig",
  341. {
  342. data: dataParsms // 传入组装好的参数
  343. },
  344. function (res) {
  345. // 打印返回结果
  346. console.log("=======================融合版安全接入网关链接res", res);
  347. if (true) { //res.err_msg === "ext_ISCP_RhConfig:ok"
  348. // resolve(res.result);
  349. wx.invoke("ext_ISCP_RhConnectCtrl", {
  350. data: {
  351. "gatewayServiceId": agentid,
  352. "connCtrlType": 1
  353. }
  354. }, function (res) {
  355. console.log("2ISCP 融合版 链接或断开 网关控制接口:", res);
  356. // res.err_msg === "ext_ISCP_RhConnectCtrl:ok"
  357. if (true) {
  358. // 成功处理
  359. resolve(res.result);
  360. } else {
  361. responseText = JSON.stringify(res);
  362. reject(40056);
  363. }
  364. });
  365. // 获取本地端口
  366. // wx.invoke("ext_ISCP_RhLocalPortCtrl", {
  367. // data: {
  368. // "gatewayServiceId": 1,
  369. // "connCtrlType": "1"
  370. // }
  371. // }, function (res) {
  372. // console.log("22hLocalPort融合版安全接入网关链接成功Ctrl:", res);
  373. // resolve(res.result);
  374. // })
  375. } else {
  376. responseText = JSON.stringify(res);
  377. console.log("融合版安全接入网关失败:", responseText);
  378. // reject(40057);
  379. }
  380. }
  381. );
  382. });
  383. }
  384. // 获取密钥信息
  385. function getIsolationdmc() {
  386. return new Promise((resolve, reject) => {
  387. $.ajax({
  388. type: "GET",
  389. url: "http://127.0.0.1:" + AppInfo.result + "/test.txt",
  390. success: function (res) {
  391. //更改路径之后接口返回的加密串末尾多了2个空格,导致无法解密,手动去掉
  392. if (res) {
  393. var words = res.split(",");
  394. var myWords = mydecrypt(words[0], words[1].trim());
  395. resolve(myWords);
  396. } else {
  397. responseText = JSON.stringify(res);
  398. reject(4006);
  399. }
  400. },
  401. error: function (err) {
  402. console.log("生成秘钥失败:", err)
  403. responseText = JSON.stringify(err);
  404. reject(4006);
  405. },
  406. });
  407. });
  408. }
  409. /**
  410. * handleLogin
  411. * @desc 用户单点登录
  412. * 生产地址:https://id.sgcc.com.cn:10443/igwmobile/proxy/getUserByIgwCode
  413. * UAT地址:https://igw.isgcc.net:18443/proxy/getUserByIgwCode
  414. * @param {String} code - 第二部注册的code
  415. * @param {String} envType - 环境类型, prod 生产,uat 测试
  416. * @returns {Promise<string>} 用户信息加密串
  417. * @since 2023年09月27日 16:42:56
  418. */
  419. function handleLogin(code, envType) {
  420. if (['production', 'uat'].indexOf(envType) === -1) return;
  421. // 执行登录
  422. const URI_MAPPER = {
  423. production: 'https://id.sgcc.com.cn:10443/igwmobile/proxy/getUserByIgwCode',
  424. uat: 'https://igw.isgcc.net:18443/proxy/getUserByIgwCode'
  425. };
  426. // 获取地址
  427. const url = URI_MAPPER[envType];
  428. return new Promise((resolve, reject) => {
  429. const data = {
  430. CODE: code,
  431. appId: AppInfo.agentid
  432. };
  433. $.ajax({
  434. type: 'POST',
  435. contentType: 'application/json;charset=UTF-8', //必须有
  436. data: JSON.stringify(data),
  437. dataType: 'json',
  438. url: url,
  439. success: function (res) {
  440. const { code, message = '', data } = res;
  441. if (code === '100001') {
  442. // console.log('#IGW: handle-login ok : ', data);
  443. resolve(data);
  444. } else {
  445. console.log('#IGW: handle-login error : ', message);
  446. reject(3001);
  447. }
  448. },
  449. error: function (err) {
  450. reject(3001);
  451. }
  452. });
  453. });
  454. }
  455. //通过安全交互平台认证之后调后端接口获取用户信息
  456. function getUser() {
  457. if (!AppInfo.result) {
  458. alert("请先获取交互平台信息");
  459. return;
  460. }
  461. var url = "http://127.0.0.1:" + AppInfo.result + "/igw-isc/isc/ipw";
  462. return new Promise((resolve, reject) => {
  463. var params = {
  464. serviceTicket: "",//ticket 新版不传
  465. nameCode: nameCode
  466. };
  467. $.ajax({
  468. type: "post",
  469. url: url,
  470. data: JSON.stringify(params),
  471. contentType: "application/json",
  472. dataType: "json",
  473. success: function (response) {
  474. console.log("getUser:", response)
  475. //token
  476. sessionStorage.setItem(
  477. "IPW_UC_TOKEN",
  478. response.data.ipwToken.resultValue.value
  479. );
  480. // ! need delete
  481. //isc用户信息
  482. setStorageEncryptData("IPW_ISC_ACCOUNTINFO_SECRET", response.data.iscInfo);
  483. sessionStorage.setItem(
  484. "IPW_ISC_ACCOUNTINFO",
  485. JSON.stringify(response.data.iscInfo)
  486. );
  487. // TyEvent4007.end();
  488. // TyEvenGetUserOther.end();
  489. resolve({
  490. userId: response.data.iscInfo.userId,
  491. account: response.data.iscInfo.account,
  492. });
  493. },
  494. error: function (response) {
  495. console.log("===============getUser response", response)
  496. let tempCode;
  497. if (response.responseJSON && response.responseJSON.code) {
  498. if (response.responseJSON.code === -1) {
  499. tempCode = 1001;
  500. response.responseText = "serviceTicket参数不能为空"
  501. } else {
  502. //3002 应该是response.responseJSON.code赋予的
  503. tempCode = response.responseJSON.code;
  504. }
  505. // TyEvenGetUserOther.fail();
  506. } else {
  507. // TyEvent4007.fail();
  508. tempCode = 4007;
  509. //4007的响应体 特殊处理
  510. responseText = JSON.stringify(response);
  511. reject(tempCode);
  512. }
  513. responseText = response.responseText
  514. ? response.responseText
  515. : response.status
  516. ? response.status
  517. : "";
  518. reject(tempCode);
  519. },
  520. });
  521. });
  522. }
  523. // 统一登录入口
  524. async function onLogin(env) {
  525. //igw相关参数赋值
  526. AppInfo = {
  527. agentid: env.VUE_APP_AGENTID,
  528. corpid: env.VUE_APP_CORPID,
  529. isc_appid: env.VUE_APP_ISCAPPID,
  530. isc_secret: env.VUE_APP_ISCSECRET,
  531. ip: env.VUE_APP_IP,
  532. iscpPort: env.VUE_APP_ISCPPORT,
  533. iscpIP: env.VUE_APP_TSCPIP,
  534. user: env.VUE_APP_USER,
  535. baseUrlIp: env.VUE_APP_BASEURLIP,
  536. baseUrlPort: env.VUE_APP_BASEURLPORT,
  537. appId: env.VUE_APP_APPID,
  538. url_wxcode: env.VUE_APP_URL_WXCODE,
  539. url_ticket: env.VUE_APP_URL_TICKET,
  540. url_accesstoken: env.VUE_APP_URL_ACCESSTOKEN,
  541. url_userinfo: env.VUE_APP_URL_USERINFO,
  542. result: "",
  543. url_serve_user: env.VUE_APP_SERVICE_USER
  544. };
  545. return new Promise(async (resolve, reject) => {
  546. try {
  547. // 1. 注册程序,获取设备信息等
  548. await handleReady();
  549. // 2. 获取code
  550. wx_code = await getAuthCode("code");
  551. if (wx_code) {
  552. // 3 .建立安全链接
  553. await getIscPortBefore();
  554. AppInfo.result = await getIscPort();
  555. //获取密钥信息
  556. const decryptedMq = await getIsolationdmc();
  557. sessionStorage.setItem("YDZY_APP_ISOLATIONDMC", decryptedMq);
  558. //登录 获取加密信息
  559. // userInfo = await getUser();
  560. // 加密的用户信息
  561. const encryptedUserInfo = await handleLogin(wx_code, env.NODE_ENV);
  562. resolve(encryptedUserInfo);
  563. } else {
  564. //获取wxcode
  565. getWxCode();
  566. }
  567. } catch (error) {
  568. errorCode = error;
  569. reject(errorCode);
  570. }
  571. });
  572. }