电子政务系统的扫码登录——国密加密轮询的完整实现不是微信扫码、不是钉钉扫码。是政务系统自己的电子社保卡扫码登录——后台调一卡通平台接口国密SM4加密通信前端轮询等待用户手机确认。每一步都是生产环境跑过的代码。文章目录电子政务系统的扫码登录——国密加密轮询的完整实现一、为什么政务系统需要扫码登录二、完整流程四个角色协作三、获取二维码——国密SM4加密通信四、轮询扫码结果——等待手机端确认五、前端轮询——每2秒查一次结果六、后端登录处理——身份证号反查操作员七、二维码过期与超时控制八、安全要点8.1 国密SM4全链路加密8.2 二维码值ewmz一次性8.3 登录事件审计九、结语一、为什么政务系统需要扫码登录政务经办系统的操作员每天登录几十次——上午登进去办几个业务出去开个会回来会话过期又要重新输密码。密码是大小写数字特殊字符输错三次锁账户解锁要找管理员。扫码登录解决的正是这个痛点手机上有电子社保卡APP打开扫一下电脑屏幕上的二维码直接登录。不需要记密码不需要找管理员重置。二、完整流程四个角色协作浏览器登录页 后台eSiCardLogin 一卡通平台 │ │ │ │ ① GET ?type_(空) │ │ │─────────────────────────────→│ │ │ │ ② getQrCode() │ │ │──────────────────────────────→│ │ │ ③ 返回二维码数据(token) │ │ ④ JSON: {qrcode数据} │←──────────────────────────────│ │←─────────────────────────────│ │ │ │ │ │ ⑤ qrcode.min.js生成二维码 │ │ │ 用户手机扫码确认 │ │ │ │ │ │ ⑥ GET ?type_getResultewmz │ │ │─────── 每2秒轮询一次 ───────→│ │ │ │ ⑦ getResult(ewmz) │ │ │──────────────────────────────→│ │ │ ⑧ 返回身份证号(aac002) │ │ │←──────────────────────────────│ │ │ ⑨ 查user表获取操作员信息 │ │ │ ⑩ 写入session 代办任务 │ │ ⑪ JSON: {code:00} │ │ │←─────────────────────────────│ │ │ ⑫ 跳转主页面 │ │三、获取二维码——国密SM4加密通信publicStringgetQrCode()throwsException{StringuserXXXXX;// 应用编码从配置文件读取// 请求参数——服务编码、渠道编号、超时时间、随机数Stringparam{\header\:{\appcode\:\user\,\servicecode\:\10138200\,\paramin\:\渠道编号\,\overtime\:\10\,\random\:\1590022782161\},\body\:{\aaz570\:\XXXXXXXXXX\}};StringurlconfigUtil.get(ykt_url);StringkeyconfigUtil.get(sm4_key);// SM4密钥从配置文件读取SmUtilfunewSmUtil();// SM4加密——经UTF-8转码用SM4加密再转16进制Stringjson{\appcode\:\user\,\security\:\fu.sm4Add16(key,param)\};// HTTP POST 发送加密请求HttpURLConnectionconn(HttpURLConnection)(newURL(url)).openConnection();conn.setRequestMethod(POST);conn.setDoOutput(true);conn.setRequestProperty(Content-Type,application/json;charsetutf-8);conn.connect();BufferedWriteroutnewBufferedWriter(newOutputStreamWriter(conn.getOutputStream(),utf-8));out.write(json);out.flush();// 读取响应——加密返回BufferedReaderinnewBufferedReader(newInputStreamReader(conn.getInputStream(),UTF-8));Stringline;StringBuildersbnewStringBuilder();while((linein.readLine())!null)sb.append(line);// SM4解密返回数据JSONObjectobjectJSONObject.fromObject(sb.toString());StringJsonencryptobject.getString(encrypt);Stringdelencryptfu.sm4Del16(key,Jsonencrypt);JSONObjectout_objectJSONObject.fromObject(delencrypt);returnout_object.get(body).toString();}请求参数明文→SM4加密→16进制→发送。返回数据→SM4解密→解析JSON。全程国密符合政务系统信创合规要求。服务编码10138200是一卡通平台的获取二维码接口。不同的服务编码代表不同的业务——10138201是轮询扫码结果的接口。四、轮询扫码结果——等待手机端确认publicStringgetResult(Stringewmz)throwsException{// 相同的加密流程不同的服务编码和参数Stringparam{\header\:{\appcode\:\user\,\servicecode\:\10138201\,// 查询扫码结果的服务编码\paramin\:\渠道编号/二维码值\,\overtime\:\20\,\random\:\123456\},\body\:{\aaz570\:\9400000303\,\ewmz\:\ewmz\}// 传入二维码值};// SM4加密 → 发送 → SM4解密 → 解析// ... 相同加密流程 ...JSONObjectout_objectJSONObject.fromObject(delencrypt);Stringoutstrout_object.getString(body);out_objectJSONObject.fromObject(outstr);returnout_object.get(aac002).toString();// 返回身份证号}用户手机扫码后一卡通平台把二维码值和用户身份绑定。后台轮询时传入相同的ewmz二维码值平台返回该用户的身份证号。服务编码10138201的超时时间设为20秒——比获取二维码的10秒更长因为用户扫码确认需要时间。五、前端轮询——每2秒查一次结果// 获取二维码$.get(/eSiCardLogin,function(data){// 用qrcode.min.js生成二维码图片varqrcodenewQRCode(document.getElementById(qrcode),{text:data.qrcode,// 二维码内容width:200,height:200});// 开始轮询——每2秒查一次vartimersetInterval(function(){$.get(/eSiCardLogin?type_getResultewmzdata.ewmz,function(result){if(result.code00){clearInterval(timer);window.location.href/pages/menu/mainframe.jsp;}});},2000);});轮询不是一直轮——有超时控制。二维码过期时间通常设为60秒超时了前端清除定时器提示二维码已过期请刷新。六、后端登录处理——身份证号反查操作员if(getResult.equals(param)){Stringewmzrequest.getParameter(ewmz);Stringaac002obj.getResult(ewmz);// 从平台拿到身份证号UserusernewUser();user.setPsn_idcard(aac002);// 用身份证号查操作员ListUserlist(ListUser)DBUtil.getDao(userMapper.class,getUserByID,user);if(list.size()1){UseruserObjlist.get(0);userObj.setIp(this.getIpAddr(request));userObj.setSessionid(session.getId());// 记录登录事件审计用DBUtil.SaveOne(userMapper.class,saveloginevent,userObj);// 写入sessionsession.setAttribute(user,userObj);// 加载待办任务loadPendingTasks(userObj,session);// 返回成功response.getWriter().print({\msg\:\登陆成功\,\code\:\00\});}}一卡通平台返回的是身份证号aac002不是系统内部的用户编号。所以需要一个getUserByID身份证号反查的Mapper方法从op_person表查到这个身份证号对应的经办操作员。登录成功后记录登录事件——谁、什么时间、从哪个IP登录。不是多此一举是政务系统的审计标配。七、二维码过期与超时控制整个扫码登录的时间窗口由三个参数控制参数位置作用overtime请求参数一卡通平台的二维码有效期轮询间隔前端JS每2秒问一次扫了没轮询总时长前端JS60秒后自动终止提示刷新这三个参数配合起来就是一次完整的扫码登录生命周期0s → 获取二维码有效期60秒 2s → 第1次轮询…未扫 4s → 第2次轮询…未扫 ... 30s → 第15次轮询…用户已扫登录成功 60s → 超时终止提示刷新二维码八、安全要点8.1 国密SM4全链路加密从请求参数到返回数据全程SM4加密。即使HTTP抓包拿到请求体看到的也是密文。密钥存在服务端配置文件里前端不可见。8.2 二维码值ewmz一次性ewmz是一卡通平台生成的随机token扫码确认后立即作废。截取当前页的二维码值无法重放——它绑定了当时生成的二维码过期或已使用后一卡通平台不再返回用户信息。8.3 登录事件审计每次扫码登录成功记录saveloginevent——操作员、登录时间、IP地址、sessionid。和传统的密码登录走同一条审计日志。九、结语政务系统的扫码登录和互联网产品不一样——后台不是调微信/支付宝的开放API是调各地人社部门的一卡通平台。加密不是TLS就够还要加一层国密SM4。前端不是WebSocket长连接是最朴素的短轮询。这套机制从2021年上线跑到系统下线没出过安全事故。不是因为用了多高级的技术——是因为每一条通信链路都加密了每一个登录都记录在案了每一个环节都能追溯。