微信公众号开发—扫描二维码实现登录方案

article/2025/9/18 7:39:39
😊 @ 作者: 一恍过去
💖 @ 主页: https://blog.csdn.net/zhuocailing3390
🎊 @ 社区: Java技术栈交流
🎉 @ 主题: 微信公众号开发—扫描二维码实现登录方案
⏱️ @ 创作时间: 2022年12月21日

目录

  • 1、准备工作
  • 2、二维码扫码登录说明
  • 3、yaml配置
  • 4、定义工具类
  • 5、扫描带参数二维码事件
  • 6、扫码登录流程示例代码

在这里插入图片描述

1、准备工作

1、调用微信公众号接口,需要实现获取AccessToken,参考《获取AccessToken接口调用凭据》
2、在本地进行联调时,为让微信端能够访问到本地服务,需要进行内网穿透,参考《本地服务器内网穿透实现(NATAPP)》
3、配置微信接口配置信息,用于告诉微信接收消息的回调地址
在这里插入图片描述

2、二维码扫码登录说明

  • 前端调用接口,后端生成二维码以及一个loginId参数(就是一个微信扫码场景值 sceneStr,loginId存入redis中,时效为5分钟);
  • 同时前端通过loginId进行轮询访问判断是否成功登录
    • 如果扫码后,用户没有进行任何绑定,则直接回复用户消息并且附带上进行绑定的引导链接(绑定操作就是一个前端页面,进入页面后用户需要同意微信网页授权、并且输入手机号、短信验证码,后端将授权后得到的code查询到openId,最后将手机号与openId进行绑定),绑定操作参考《微信网页授权自动登录业务系统》;
    • 如果扫码后,loginId已过期则要求用户重新刷新二维码,并且只要是授权不成功都需要重新刷新二维码再次执行授权流程;
    • 如果扫码后 发现以及已经绑定了openid则授权登录成功,将用户信息及token信息通过轮询接口返回到前端,并且删除loginId值;

3、yaml配置

wx:# 来源于测试平台appid: wx79ec4331f29311b9secret: 1c79a199560f94096f26b8caa2a73a08apiUrl: https://api.weixin.qq.com/openApiUrl: https://open.weixin.qq.com/authRedirectUri: http://6uks3d.natappfree.cc/wechat/auth

4、定义工具类

MapUtils:

public class MapUtils {/*** Map转换为 Entity** @param params 包含参数的Map* @param t      需要赋值的实体* @param <T>    类型*/public static <T> T mapToEntity(Map<String, Object> params, T t) {if (null == params) {return t;}Class<?> clazz = t.getClass();Field[] declaredFields = clazz.getDeclaredFields();try {for (Field declaredField : declaredFields) {declaredField.setAccessible(true);String name = declaredField.getName();if (null != params.get(name)) {declaredField.set(t, params.get(name));}}} catch (Exception e) {throw new RuntimeException("属性设置失败!");}return t;}/*** 将对象转换为HashMap** @param t   转换为Map的对象* @param <T> 转换为Map的类* @return Map*/public static <T> Map<String, Object> entityToMap(T t) {Class<?> clazz = t.getClass();List<Field> allField = getAllField(clazz);Map<String, Object> hashMap = new LinkedHashMap<>(allField.size());try {for (Field declaredField : allField) {declaredField.setAccessible(true);Object o = declaredField.get(t);if (null != o) {hashMap.put(declaredField.getName(), o);}}} catch (Exception e) {throw new RuntimeException("属性获取失败!");}return hashMap;}/*** 获取所有属性** @param clazz class* @param <T>   泛型* @return List<Field>*/public static <T> List<Field> getAllField(Class<T> clazz) {List<Field> fields = new ArrayList<>();Class<?> superClazz = clazz;while (null != superClazz) {fields.addAll(Arrays.asList(superClazz.getDeclaredFields()));superClazz = superClazz.getSuperclass();}return fields;}/*** 将Map参数转换为字符串** @param map* @return*/public static String mapToString(Map<String, Object> map) {StringBuffer sb = new StringBuffer();map.forEach((key, value) -> {sb.append(key).append("=").append(value.toString()).append("&");});String str = sb.toString();str = str.substring(0, str.length() - 1);return str;}/*** 将Bean对象转换Url请求的字符串** @param t* @param <T>* @return*/public static <T> String getUrlByBean(T t) {String pre = "?";Map<String, Object> map = entityToMap(t);return pre + mapToString(map);}}

在这里插入图片描述

5、扫描带参数二维码事件

@Service
@Slf4j
public class MessageService {@Resourceprivate ScanAuthService scanAuthService;public String receiveAndResponseMessage(HttpServletRequest request) {log.info("------------微信消息开始处理-------------");try {// 调用消息工具类MessageUtil解析微信发来的xml格式的消息,解析的结果放在HashMap里;Map<String, String> map = WeixinMessageUtil.xmlToMap(request);String jsonString = JSON.toJSONString(map);// 发送方账号(用户方)String fromUserName = map.get("FromUserName");// 接受方账号(公众号)	String toUserName = map.get("ToUserName");// 消息类型String msgType = map.get("MsgType");log.info("fromUserName is:" + fromUserName + " toUserName is:" + toUserName + " msgType is:" + msgType);// 事件类型String eventType = map.get("Event");if (eventType.equals(MessageType.EVENT_TYPE_SCAN)) {BaseEvent message = JSON.parseObject(jsonString, BaseEvent.class);log.info("扫码成功 {}", message);// 事件 KEY 值,qrscene_为前缀,后面为二维码的参数值String eventKey = map.get("EventKey");String openId = message.getFromUserName();// 进行后续的授权处理if (!StringUtils.isEmpty(eventKey)) {scanAuthService.getAuth(openId, eventKey);}}} catch (Exception e) {e.printStackTrace();log.error("系统出错");return null;}}
}

6、扫码登录流程示例代码

扫码请求实体类定义:

@Data
public class QrCodeRep {/*** 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒*/private Integer expire_seconds;/*** 二维码类型* QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值* QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值*/private String action_name;/*** 二维码详细信息*/private ActionInfo action_info;@Datapublic static class ActionInfo {private Scene scene;}@Datapublic static class Scene {/*** 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64*/private String scene_str;}
}

扫码请求响应类定义:

@Data
public class QrCodeRes {/*** 获取的二维码ticket,凭借此 ticket 可以在有效时间内换取二维码。*/private String ticket;/*** 通过ticket换取的二维码*/private String ticketUrl;/*** 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天)*/private Integer expire_seconds;/*** 二维码图片解析后的地址,开发者可根据该地址自行生成需要的二维码图片*/private String url;/*** 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64*/private String sceneStr;
}

Service层:

@Slf4j
@Service
public class ScanAuthService {@Resourceprivate WeChantService weChantService;@Resourceprivate RestHttpRequest restHttpRequest;@Resourceprivate UserInfoMapper userInfoMapper;@Resourceprivate WxBean wxBean;public String getAuth(String openId, String loginId) {String msg = "扫码登录成功!";// 如果扫码后,loginId已过期则要求用户重新刷新二维码,并且只要授权不成功都需要重新刷新二维码再次执行授权流程if (!RedisUtils.hasKey(loginId)) {msg = "扫码登录已过期,请重新刷新二维码!";}Object o = RedisUtils.get(loginId);if (o == null) {msg = "扫码登录已过期,请重新刷新二维码!";} else {ScanStatusAuthRes authRes = JSON.parseObject(o.toString(), ScanStatusAuthRes.class);UserInfo userInfo = userInfoMapper.selectByOpenId(openId);if (userInfo == null) {// 如果扫码后,如果没有进行任何绑定,则直接回复用户消息并且附带上进行绑定的链接msg = "<a href =\"https://www.baidu.com/\">请前往绑定</a>";RedisUtils.del(loginId);}// 如果扫码后 发现以及已经绑定了openid则授权登录成功,将用户信息及token信息通过轮询接口返回到前端,并且删除loginId值authRes.setStatus(2);authRes.setUserInfo(userInfo);long expire = RedisUtils.getExpire(loginId);RedisUtils.setEx(loginId, JSON.toJSONString(authRes), expire, TimeUnit.SECONDS);}return msg;}public PageResult qrcodeCreate() {String url = wxBean.getApiUrl() + InterfaceConstant.QR_CODE_CREATE;BaseRep rep = new BaseRep();rep.setAccess_token(weChantService.getAccessToken());url = url + MapUtils.getUrlByBean(rep);QrCodeRep codeRep = new QrCodeRep();codeRep.setAction_name("QR_STR_SCENE");codeRep.setExpire_seconds(5 * 60);QrCodeRep.ActionInfo actionInfo = new QrCodeRep.ActionInfo();QrCodeRep.Scene scene = new QrCodeRep.Scene();// 设置场景值String loginId = UUIDUtils.getUuId();scene.setScene_str(loginId);actionInfo.setScene(scene);codeRep.setAction_info(actionInfo);Map map = restHttpRequest.doHttp(url, HttpMethod.POST, codeRep);QrCodeRes res = new QrCodeRes();MapUtils.mapToEntity(map, res);res.setSceneStr(scene.getScene_str());try {// 通过ticket获取二维码String ticket = res.getTicket();String ticketUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + URLEncoder.encode(ticket, "UTF-8");res.setTicketUrl(ticketUrl);} catch (UnsupportedEncodingException e) {e.printStackTrace();}// 将状态写入redisScanStatusAuthRes authRes = new ScanStatusAuthRes();authRes.setStatus(1);RedisUtils.setEx(loginId, JSON.toJSONString(authRes), res.getExpire_seconds(), TimeUnit.SECONDS);return ResultUtils.success(res);}public PageResult scanStatus(String loginId) {// 通过redis查询是否存在if (!RedisUtils.hasKey(loginId)) {return ResultUtils.fail("扫码登录已过期,请重新刷新二维码!");}Object o = RedisUtils.get(loginId);ScanStatusAuthRes authRes = JSON.parseObject(o.toString(), ScanStatusAuthRes.class);if (authRes.getStatus() == 2) {// 删除keyRedisUtils.del(loginId);}return ResultUtils.success(authRes);}
}

Controller层:

@Slf4j
@RestController
public class ScanAuthController {@Resourceprivate ScanAuthService scanAuthService;/*** 获取扫码登录二维码** @return*/@ApiOperation(value = "获取扫码登录二维码", notes = "获取扫码登录二维码")@GetMapping("/scanLogin")public PageResult qrcodeCreate() {return ResultUtils.success(scanAuthService.qrcodeCreate());}/*** 轮询获取登录状态** @param loginId* @return*/@ApiOperation(value = "轮询获取登录状态", notes = "轮询获取登录状态")@GetMapping("/scanStatus")public PageResult scanStatus(@RequestParam("loginId") String loginId) {return ResultUtils.success(scanAuthService.scanStatus(loginId));}
}

在这里插入图片描述


http://chatgpt.dhexx.cn/article/S2xGt6od.shtml

相关文章

第三方登录之微信扫码登录

文章目录 1. 申请微信接入&#xff1a;2. 项目环境搭建&#xff1a;3.后端Controller接口&#xff1a;4.HTML页面代码&#xff1a;5.测试结果&#xff1a;6.补充说明&#xff1a; 小伙伴们有各种疑问可以去参考官方文档进行详细的学习下 微信开发文档 &#xff0c;此次介绍的将…

扫码登录操作过程

转载自http://justcoding.iteye.com/blog/2213661浏览器输入&#xff1a;https://wx.qq.com/?langzh_CN手机登录微信&#xff0c;利用“扫一扫”功能扫描网页上的二维码手机扫描成功后&#xff0c;提示“登录网页版微信”&#xff1b;网页上显示“成功扫描 请在手机点击确认以…

实现手机扫描二维码进行登录

项目结构&#xff1a; 实现流程&#xff1a; pc端&#xff1a; 1:打开二维码登录网页index.html 2:index.html调用GetQrCodeServlet 3:GetQrCodeServlet干2件事 a:生成随机的uuid,是一个唯一标识&#xff0c;该标识贯穿整个流程 b:生成二维码图片&#xff0c;二维码信息&#x…

扫码登录,背后是如何实现的?

引言 近年来&#xff0c;随着智能手机和移动支付的普及以及互联网应用的不断更新迭代&#xff0c;扫码登录已经成为了我们日常生活中非常普遍的登录方式。扫码登录能够迅速的成为我们各大网站常用的登录方式一定存在它的原因。 首先一个非常重要的原因&#xff0c;扫码登录还可…

网站实现微信扫码登录

网站实现微信扫码登录 1 准备工作1.1 申请网站应用 2 快速开始2.1 微信扫码登录流程说明2.2 生成微信二维码的两种方式2.2.1 微信提供的二维码生成URL2.2.2 将微信登录二维码内嵌到自己页面 2.3 系统微信扫码登录示例2.3.1 流程说明2.3.2 核心代码2.3.2.1 前端代码2.3.2.2 后端…

【一】微信公众号之扫码登录

微信公众号之扫码登录 ​ 原来公司的官网就支持账号密码、手机验证码、QQ扫码授权、微信扫码授权等多种登录方式。今天要分享的就是关于微信扫码授权登录的原理。 一、准备工作 使用的是微信登录功能实现的&#xff0c;需要先在微信开放平台注册开发者帐号&#xff0c;并拥有一…

公众号扫码登录

1.流程概述 1.1 申请公众号 1.2 创建带参数的公众号二维码&#xff0c;参数值为scen_id的值 1.3 微信基础配置接口编写&#xff0c;get方式的接口为微信测试接口&#xff0c;必须能正常访问&#xff0c;post方式的接口为扫码回调接口&#xff0c;从请求中获取微信返回的xml包…

二维码扫描登录,你必须知道的 3 件事!

作者 | 互联网平头哥 本文经授权转载自互联网平头哥&#xff08;ID&#xff1a;it_pingtouge&#xff09; 扫二维码登录现在比较常见&#xff0c;比如微信、支付宝等 PC 端登录&#xff0c;并且好像每款 APP 都支持扫码登录&#xff0c;不搞个扫码登录都不好意思。作为技术人员…

微信扫码登录实现

需求 使用微信扫码登录的授权方式登录系统 实现 此扫码登陆过程中使用了&#xff0c;微信开放平台&#xff08;需支付300开通开发者认证&#xff09;的网站应用实现的。 官方文档&#xff1a;https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wec…

web扫码登录

文章目录 需求流程交互流程服务交互流程 关键思路代码生成二维码&#xff0c;返回给PC展示轮询查询二维码状态APP扫码请求登录 总结 需求 pc端实现app扫码登录 流程 交互流程 服务交互流程 关键思路 主要问题在于如何识别APP端用户&#xff0c;然后传递给PC端已经登录成功 …

开放平台–扫描微信二维码登录

准备 如不了解第三方登录流程&#xff0c;建议先大概了解一下&#xff0c;在来看看代码。 说明&#xff1a; 由于开放平台无测试号测试&#xff0c;所以只能上开放平台进行配置信息。公众平台的测试号并不能给开放平台使用。 微信开放平台地址&#xff1a;https://open.weixi…

二维码登陆

上一段时间研究微信公共账号,发现微信提供了一个扫码登陆验证的功能。近期头痛于经常忘记用户名密码,因此考虑是否可以结合这个功能,完成免密码登陆。百度后发现&#xff0c;有很多仁兄已经做过类似的功能了。 如这篇文章: 实现网站二维码扫描登录 仔细研究后&#xff0c;发现很…

二维码登录(三)扫码登录

承接上篇博客&#xff0c;在进行二维码生成之后&#xff0c;app进行扫码&#xff0c;扫码成功之后&#xff0c;手机点击登录&#xff0c;进行绑定登录关系&#xff0c;后台做自动关联与自动登录。 本文git地址&#xff1a;https://github.com/xvshu/qrlogin 1&#xff0c;扫码…

微信扫码登陆(1)---扫码登录流程讲解、获取授权登陆二维码

扫码登录流程讲解、获取授权登陆二维码 具体流程可以看微信官网的扫码登录文档 地址&#xff1a;准备工作 | 微信开放文档 其实官方文档已经讲的非常清楚而且讲的也很明白。 一、扫码登录流程讲解 1、首先准备工作 网站应用微信登录是基于OAuth2.0协议标准构建的微信OAut…

二维码扫码登录

项目结构 模块介绍 流程1 pc端&#xff1a;1:打开二维码登录网页index.html2:index.html调用GetQrCodeServlet3:GetQrCodeServlet干2件事 a:生成随机的uuid,是一个唯一标识&#xff0c;该标识贯穿整个流程 b:生成二维码图片&#xff0c;二维码信息&#xff1a;http://60.2…

扫码登录详解

目录 扫码流程分析 流程详解 步骤一&#xff1a;PC端准备二维码 步骤三&#xff1a;状态确认 token认证机制 扫码流程分析 1.扫码前&#xff0c;手机端已经是登陆状态&#xff0c;PC端显示一个二维码&#xff0c;等待扫描。 2.手机端打开应用&#xff0c;扫描PC端的二维码…

新增商品

1、在http代理设置&#xff0c;添加过滤参数&#xff1a; .*pusher\.*\/websocket.* .*/venilog/log/one .*\.(bmp|css|js|gif|ico|jpe?g|png|swf|woff) .*pusher\/info.* 2、启动http代理设置&#xff0c;录制脚本&#xff0c;将登陆和发布商品的脚本修改成’登陆‘&#x…

自定义商品分类,选择分类之后,添加商品附属性;仿淘宝后台添加商品附属性的价格和数量

效果图&#xff08;图片较大&#xff0c;加载较慢&#xff09; 页面部分&#xff1a; <div class"layui-form-item" id"add_attribute"><label class"layui-form-label">商品分类</label><div class"layui-input-i…

javaScript原生版购物车:全选、单选、全删、商品数量增减、计算总价、添加商品(代码)

题目&#xff1a; CSS代码如下&#xff1a; <style> *{ margin: 0px; padding: 0px; } .header,.content,.floot{ width: 800px; margin:0px auto; } .header ul li,.content ul li{ float: left; list-style: none; width: 100px; line-height: 100px; text-align: cen…

商品管理的新增

实现的功能如下&#xff1a; 点击新增弹出新增模态框通过下拉框绑定商品类别和商品单位保存新增 主要代码&#xff1a; 以上就是我的分享&#xff0c;如果有更好的方法或不懂得地方欢迎在评论区教导和提问喔&#xff01;