diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfLoginController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfLoginController.java index 18921ac8..cdf0cae8 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfLoginController.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfLoginController.java @@ -1,20 +1,26 @@ package com.zdxt.enforcementcode.controller.app.enforcement; import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; import com.zdxt.enforcementcode.common.commonenum.PlatformTypeEnums; import com.zdxt.enforcementcode.common.util.CommonUtil; +import com.zdxt.enforcementcode.controller.app.utils.HttpUtil; import com.zdxt.enforcementcode.service.enforcement.IAppEnfLoginService; import com.zdxt.enforcementcode.controller.app.LoginController; import com.zdxt.enforcementcode.domain.vo.SrzDeptVo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Hex; import org.dromara.common.core.domain.R; import org.dromara.system.domain.vo.SysDeptVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.service.ISysDeptService; import org.dromara.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; @@ -31,6 +37,15 @@ public class AppEnfLoginController extends LoginController { private final ISysDeptService sysDeptService; private final IAppEnfLoginService appEnfLoginService; + @Value("${szypt.corpid}") + private String szyptCorpid; + @Value("${szypt.agentid}") + private String szyptAgentid; + @Value("${szypt.corpsecret}") + private String szyptCorpsecret; + @Value("${szypt.url}") + private String szyptUrl; + /** * 执法端用户登录 * @@ -141,4 +156,60 @@ public class AppEnfLoginController extends LoginController { String code = params.get("code"); return appEnfLoginService.szyptLogin(code); } + + /** + * 深圳易平台使用权限签名算法 + */ + @GetMapping("/szyptGetToken") + @ResponseBody + public R> szyptGetToken(@RequestParam("code") String code, @RequestParam("url") String url){ + try { + System.out.println("====================== 获取政务微信认证签名URL ======================"); + log.info("获取政务微信认证签名code:{}",code); + log.info("获取政务微信认证签名URL:{}",url); + // 获取 access_token + String accessTokenJson = HttpUtil.HttpSendGet(szyptUrl + "/cgi-bin/gettoken?corpid="+szyptCorpid+"&corpsecret="+szyptCorpsecret, null); + JSONObject tokenObj = JSONObject.parseObject(accessTokenJson); + String token = tokenObj.getString("access_token"); + String jsapiTicket = HttpUtil.HttpSendGet(szyptUrl + "/cgi-bin/get_jsapi_ticket?access_token="+token, null); + JSONObject ticketObj = JSONObject.parseObject(jsapiTicket); + String ticket = ticketObj.getString("ticket"); + log.info("====================== jsapiTicket start ======================"); + log.info("ticket: {}",ticket); + log.info("====================== jsapiTicket end ======================"); + + long timestamp = System.currentTimeMillis() / 1000; + //随机字符串 + String nonceStr = "Wm3WZYTPz0wzccnW"; + String signature = getSignature(ticket, nonceStr, timestamp, url); + log.info("signature: {}",signature); + + Map data = new HashMap<>(); + data.put("agentid", szyptAgentid); + data.put("corpid", szyptCorpid); + data.put("timestamp", timestamp); + data.put("nonceStr", nonceStr); + data.put("signature", signature); + return R.ok(data); + } catch (Exception e) { + log.error(e.getMessage()); + e.printStackTrace(); + } + return R.ok(); + } + + private String getSignature(String ticket, String nonceStr, long timestamp, String url) { + try { + + String unEncryptStr = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url; + MessageDigest sha = MessageDigest.getInstance("SHA"); + // 调用digest方法,进行加密操作 + byte[] cipherBytes = sha.digest(unEncryptStr.getBytes()); + String encryptStr = Hex.encodeHexString(cipherBytes); + return encryptStr; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/index.js b/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/index.js index 74826559..89ccda2b 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/index.js +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/index.js @@ -6,6 +6,9 @@ const baseUrl = "/app-enf"; export const enforcementLogin = (params, success, error) => _post(baseUrl + "/login/szyptLogin", params, success, error); export const enforcementLoginByPassword = (params, success, error) => _post(baseUrl + "/login/do", params, success, error); + +// 深圳易平台 +export const szyptGetToken = (params, success, error) => _get(baseUrl + "/login/szyptGetToken",params,success,error); // endregion // region 企业模块 diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/scanEntQRCode.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/scanEntQRCode.vue index 038fcee1..8db19f9b 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/scanEntQRCode.vue +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/scanEntQRCode.vue @@ -95,7 +95,7 @@ import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue'; import { useRouter, useRoute } from 'vue-router'; import { showFailToast, showSuccessToast, showToast, showConfirmDialog } from 'vant'; import { baseUrl, appEnv } from '@/config/env.js'; -import { getEntInfoByQRCode, queryEnterpriseListAndQrInfo } from '@/api/enforcement/index'; +import { getEntInfoByQRCode, queryEnterpriseListAndQrInfo, szyptGetToken } from '@/api/enforcement/index'; import wx from 'weixin-js-sdk'; const router = useRouter(); @@ -209,53 +209,60 @@ const onFileSelected = async (event) => { // ---------- prod 环境:wx.scanQRCode ---------- const openWxScan = () => { - // TODO: 对接实际微信 JSSDK token 接口后启用 - // 当前仅预留调用骨架,需配合服务端 szyptGetToken 接口获取签名 - const fullUrl = window.location.href; - const paramUrl = fullUrl.split('#')[0]; - showToast('正在调起微信扫码...'); - // 以下为 wx.config + wx.scanQRCode 的标准流程 - // 实际使用时需先调用服务端接口获取 config 参数 - szyptGetToken({ url: paramUrl }, (res) => { - const data = res.data; - wx.config({ - debug: false, - appId: data.corpid, - timestamp: data.timestamp, - nonceStr: data.nonceStr, - signature: data.signature, - jsApiList: ['scanQRCode'], - }); - wx.ready(() => { - wxClickScan(); - }); - wx.error((err) => { - console.error('wx.config 失败', err); - showFailToast('微信配置失败,请重试'); + let fullUrl = window.location.href; + let code = fullUrl.substring(fullUrl.indexOf('code=') + 5, fullUrl.indexOf('&state=')); + let paramUrl = window.location.href.split("#")[0]; + let param = {code: code, url: paramUrl}; + szyptGetToken(param, success => { + let resMsg = success.data; + console.log(resMsg); + wx.config({ + // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 + debug: false, + // 必填,公众号的唯一标识 + appId: resMsg.corpid, + // 必填,生成签名的时间戳 + timestamp: resMsg.timestamp, + // 必填,生成签名的随机串 + nonceStr: resMsg.nonceStr, + // 必填,签名,见附录1 + signature: resMsg.signature, + // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 + jsApiList: ["scanQRCode"], + }); + wx.ready(() => { + //微信扫一扫请求操作 + ClickScan() + }); + wx.error((res) => { + console.log("获取失败", res); + }); + }, error => { }); - }); - - - // 开发阶段直接尝试调用(在微信浏览器内有效) - wxClickScan(); }; -const wxClickScan = () => { +const ClickScan = () => { wx.scanQRCode({ - needResult: 1, - scanType: ['qrCode', 'barCode'], + needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, + scanType: ['qrCode', 'barCode'], // 可以指定扫二维码还是一维码,默认二者都有 success: (res) => { - console.log('wx 扫码返回:', res); - handleScanResult(res.resultStr); + // 页面跳转 + console.log("=========== 扫码返回 ===========") + console.log(res) + if(isHttpLink(res.resultStr)){ + handleScanResult(res.resultStr); + }else{ + showFailToast("该二维码不正确"); + } }, - error: (res) => { - console.error('wx 扫码错误:', res); - if (res.errMsg && res.errMsg.indexOf('function_not_exist') > 0) { - showFailToast('版本过低请升级'); + error: function(res) { + console.log("错误回调",res) + if (res.errMsg.indexOf('function_not_exist') > 0) { + showFailToast('版本过低请升级') } }, - cancel: () => { - console.log('用户取消扫码'); + cancel: (res) => { + console.log('err', res); }, }); }; @@ -279,7 +286,7 @@ const handleScanResult = (resultStr) => { // 将企业信息存入 sessionStorage,预览页直接使用,无需再调接口 sessionStorage.setItem('enterpriseScanData', JSON.stringify(data)); // 跳转企业详情预览页,携带执法类型参数和企业编号 - router.push({ + router.push({ path: '/enforcement/enterpriseScanPreview', query: { type: enforceType, enterpriseNumber: data.enterpriseNumber } }); @@ -394,7 +401,7 @@ const selectEnterprise = (item) => { showSearchModal.value = false; router.push({ path: '/enforcement/enterpriseScanPreview', - query: { + query: { enterpriseNumber: item.enterpriseNumber, type: enforceType }