简介
电脑端微信网页扫码授权登录有2种方式:
第一种:基于微信公众号,单独获取登录二维码扫码,然后扫码登录,程序控制跳转逻辑,例如CSDN:
第二种:基于微信开放平台,跳转到微信二维码页面进行扫码登录,重定向到成功页面,例如有道笔记: 注: 本文记录第一种方式,只需通过微信测试公众号即可完成完整测试,即所有人本地都可以完整运行;第二种需有通过认证资质的开发者账号,后续再记录。
本地完整运行环境准备
内网渗透=>生成本地指定端口映射的外网域名
传送门:内网渗透工具Natapp使用详解 域名生成之后修改配置文件:
注册并配置微信测试公众号
注册地址:微信公众平台 测试账号申请,扫码登录,并关注该测试号
1.获取测试号appid和appsecret
2.接口配置信息修改(此处会回调后台签名验证方法,配置时需启动后台)
3.配置网页授权域名,用于获取微信用户信息
流程
文字简述
页面点击获取微信登录二维码按钮
后台以appid和appsecret为参数调用微信api获取access_token
以access_token为参数调用微信api获取本地微信登录二维码ticket,同时传随机字符串参数scene_str,该参与可用于程序验证是否扫码成功
通过ticket获取二维码成功,页面显示,同时前台开始进行js定时任务(此处可优化成后台通知),监听是否扫码成功
用户微信扫码成功
微信服务器端回调本地服务器签名验证接口验证签名和回调处理
回调处理确定扫码成功(此处还可进行关注验证),数据库或缓存插入本地扫码成功记录
前台定时任务获取到扫码成功记录或者后台主动通知,进行扫码成功后业务处理
代码
1.获取微信二维码和启动js定时任务
前台html
<h1>微信扫码登录方式一</h1><buttononclick="getQrCode()"style="width:100px;height:50px;">获取二维码</button><br><imgsrc=""id="qrCodeImgId"style="width:300px;height:300px;display:none"><hr>
前台js
//======================================微信扫码登录方式一=========================================================//存储二维码标识,用于验证是否扫码成功varsceneStr;vart;//获取登录二维码functiongetQrCode(){$.get('qrCodeFirstLogin/getQrCode',function(data){console.log("=============getQrCode=======================");console.log(data);if(data.code==200){sceneStr=data.data.sceneStr;//二维码获取$('#qrCodeImgId').attr('src',"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket="+data.data.ticket);$('#qrCodeImgId').show();//定时任务监听是否扫码成功t=window.setInterval(getOpenId,3000);}else{alert(data.msg);}});}
后台获取二维码ticket接口
/***获取accessToken*@return*/publicStringgetAccessToken(){StringaccessToken=null;StringgetTokenUrl=wxConfig.getTokenUrl().replace("APPID",wxConfig.getAppId()).replace("SECRET",wxConfig.getAppSecret());Stringresult=HttpClientUtil.doGet(getTokenUrl);JSONObjectjsonObject=JSONObject.parseObject(result);accessToken=jsonObject.getString("access_token");returnaccessToken;}/***获取登录二维码*@return*/@GetMapping("/getQrCode")privateResultJsongetQrCode(){try{//获取token开发者StringaccessToken=getAccessToken();StringgetQrCodeUrl=wxConfig.getQrCodeUrl().replace("TOKEN",accessToken);//这里生成一个带参数的二维码,参数是scene_strStringsceneStr=CodeLoginUtil.getRandomString(8);Stringjson="{\"expire_seconds\":604800,\"action_name\":\"QR_STR_SCENE\""+",\"action_info\":{\"scene\":{\"scene_str\":\""+sceneStr+"\"}}}";Stringresult=HttpClientUtil.doPostJson(getQrCodeUrl,json);JSONObjectjsonObject=JSONObject.parseObject(result);jsonObject.put("sceneStr",sceneStr);returnResultJson.ok(jsonObject);}catch(Exceptione){e.printStackTrace();returnResultJson.error(e.getMessage());}}
2.签名验证和回调处理
/***验证签名*@paramrequest*@return*@throwsException*/@RequestMapping("/checkSign")publicStringcheckSign(HttpServletRequestrequest)throwsException{log.info("===========>checkSign");//获取微信请求参数Stringsignature=request.getParameter("signature");Stringtimestamp=request.getParameter("timestamp");Stringnonce=request.getParameter("nonce");Stringechostr=request.getParameter("echostr");//参数排序。token就要换成自己实际写的tokenString[]params=newString[]{timestamp,nonce,"123456"};Arrays.sort(params);//拼接Stringparamstr=params[0]+params[1]+params[2];//加密//获取shal算法封装类MessageDigestSha1Dtgest=MessageDigest.getInstance("SHA-1");//进行加密byte[]digestResult=Sha1Dtgest.digest(paramstr.getBytes("UTF-8"));//拿到加密结果Stringmysignature=CodeLoginUtil.bytes2HexString(digestResult);mysignature=mysignature.toLowerCase(Locale.ROOT);//是否正确booleansignsuccess=mysignature.equals(signature);//逻辑处理if(signsuccess&&echostr!=null){//peizhitokenreturnechostr;//不正确就直接返回失败提示.}else{JSONObjectjsonObject=callback(request);returnjsonObject.toJSONString();}}/***回调方法*@paramrequest*@return*@throwsException*/publicJSONObjectcallback(HttpServletRequestrequest)throwsException{log.info("===========>callback");//request中有相应的信息,进行解析WxMpXmlMessagemessage=WxMpXmlMessage.fromXml(request.getInputStream());//获取消息流,并解析xmlStringmessageType=message.getMsgType();//消息类型StringmessageEvent=message.getEvent();//消息事件//openidStringfromUser=message.getFromUser();//发送者帐号Stringtouser=message.getToUser();//开发者微信号Stringtext=message.getContent();//文本消息文本内容//生成二维码时穿过的特殊参数StringeventKey=message.getEventKey();//二维码参数Stringuuid="";//从二维码参数中获取uuid通过该uuid可通过websocket前端传数据Stringuserid="";//if判断,判断查询JSONObjectjsonObject=newJSONObject();jsonObject.put("code","200");if(messageType.equals("event")){jsonObject=null;//先根据openid从数据库查询=>从自己数据库中查取用户信息=>jsonObjectif(messageEvent.equals("SCAN")){//扫描二维码//return"欢迎回来";}if(messageEvent.equals("subscribe")){//关注//return"谢谢您的关注";}//没有该用户if(jsonObject==null){//从微信上中拉取用户信息Stringurl="https://api.weixin.qq.com/cgi-bin/user/info?access_token="+getAccessToken()+"&openid="+fromUser+"&lang=zh_CN";Stringresult=HttpClientUtil.doGet(url);jsonObject=JSONObject.parseObject(result);/***用户信息处理....*/}//扫码成功,存入缓存loginMap.put(eventKey,newCodeLoginKey(eventKey,fromUser));returnjsonObject;}returnjsonObject;//log.info("消息类型:{},消息事件:{},发送者账号:{},接收者微信:{},文本消息:{},二维码参数:{}",messageType,messageEvent,fromUser,touser,text,eventKey);}
3.扫码成功获取用户信息取消定时任务
js定时任务监听
//扫码成功,获取用户openId=>为获取用户信息做准备functiongetOpenId(){$.get("qrCodeFirstLogin/getOpenId",{"eventKey":sceneStr},function(data){if(data.code==200){console.log("========getOpenId==========");console.log(data.data);window.clearInterval(t);alert("登录成功openId:"+data.data.openId);/***1、第一次扫码登录进行账号绑定*2、以后根据openId获取用户信息*/}});}
后台验证接口
/***根据二维码标识获取用户openId=>获取用户信息*@parameventKey*@return*/@RequestMapping("getOpenId")publicResultJsongetOpenId(StringeventKey){if(loginMap.get(eventKey)==null){returnResultJson.error("未扫码成功!");}CodeLoginKeycodeLoginKey=loginMap.get(eventKey);loginMap.remove(eventKey);returnResultJson.ok(codeLoginKey);}
结果演示
获取二维码
扫码成功
完整源码
传送门:微信pc扫码登录