个人网站实现微信扫码登录

news2024/11/18 1:43:12

⭐个人网站实现微信扫码登录

总体结构

🥈效果图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzSrNgiv-1685034480658)(https://img.ggball.top/picGo/动画.gif)]

📗开发背景

为什么想用微信扫码登录呢?
起因是自己开发了一个搜题网站,内容很简单,但是没有登陆,所以游客可以随便使用,当然也不是不让游客访问,只是没有登陆的话,不能很好的统计使用的用户,也能减少些一些滥用的用户。

起初,我是想设计成账号密码登录网站的,但是想了下,我自己平常碰到一些需要注册的网站,我往往会直接跳过,就不会对这个网站感兴趣了,能让我感兴趣的网站一般都是支持直接扫码登录或者可以以第三方账号直接注册登录,所以能吸引更多的用户,必须要把这个门槛给打下来,提高用户体验!

📖寻找方案,以及选择哪种方案

于是,我开始踏上了百度之旅,经过数次的查阅资料,发现有三种方式实现微信扫码登录

  • 第三方网站(https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html)
  • 公众号
  • 小程序

第三方网站

第三方网站方式是直接请求api,https://open.weixin.qq.com/connect/qrconnect带上下面的参数
例子:携带参数的链接
qrconnect接口参数

页面会重定向到一个附带临时code的地址

重定向链接

用户扫码成功后,页面会自动跳转到redirect_uri指定的链接,这样就完成了扫码登录

总之,微信开放平台的方式应该是最舒服的微信扫码登陆了,但是前提需要交认证300元的认证费用,网站的话还需要提交《微信开放平台网站信息登记表》,也是审核最麻烦的方式,只好先pass啦
开发者认证
网站审核

公众号

必要条件:公众号是已认证好的服务号
流程:
获取codeAPI

  • 利用WxLogin获取到code,再用code通过https://api.weixin.qq.com/sns/oauth2/access_token获取access_token;
  • 拿到access_token之后,可以利用生成二维码api(可携带scene值,就是自己定义的uuid之类的,可以用来区分是哪个网页端发起的扫描)生成微信二维码;

生成二维码api

  • 当用户扫描生成好的二维码时,微信会根据推送事件到服务端(这个需要自己在后台配置),并且会携带好之前的scene值,后台就可以判断是哪个网页端扫了这个二维码,后台进行登录操作,
  • 网页端可以通过拿着scene值轮训后台的接口,查询是否登录成功
    或者利用websocket,后台主动通知你给网页,是否登录成功。

生成二维码文档地址:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html

这种方式还是对个人开发者要求太高了,个人就不能申请服务号,认证也要一笔费用,也劝退我了,pass!

小程序

条件:已经上线的小程序(个人/公司)
流程:

  1. 后台调用微信接口https://api.weixin.qq.com/cgi-bin/token获取access_token,access_token只有两个小时,因为有调用频率限制,access_token最好是保存在缓存中;
  2. 用户在网页端点击获取小程序码,前端携带随机数请求后台,后台利用access_token获取小程序码https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=(其中需要携带一个参数scene需要注意,scene值就是一个随机数,需要在前端就生成好,用来后台区分网页端用),返回小程序码二进制数据;
  3. 前端接收后台返回的二进制数据,(此时前端需要不停地轮训后台接口查询是否登录成功,或者利用websocket,后台主动通知前端)展示小程序码,用户拿出手机用微信扫码之后,类似下面截图,

登录截图

  1. 用户主动点击登录按钮,登录按钮需要绑定WxLogin事件,获取用户的微信code,再调用后台提供的登录接口进行登录操作,当登陆成功完毕,通知前端完成登录

获取小程序码官方文档 https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/qr-code/getQRCode.html

最后,整个过程全程免费,对于我来说也是比较简单的,我先说明下,我之前是开发了一个小程序的,所以对我来说是比较方便的,如果大家没有已经上线的小程序,为了一个扫码登录,确实有点费力

🦯原理

原理图

原理图

👞开发步骤

这里我就不细讲了,知道了思路,其实开发就是最简单的事了,这里贴一些关键的代码

网页端

    // 获取二维码
    getQrcode = () => {

        // 创建websocket连接,为了后台能主动通知到前端
        if (this.state.ws == null) {
            this.setState({
                ws: this.createWebSocket(this)
            });
        }

        // 发送请求 获取二维码
        this.setState({
            qrcodeBase64: ''
        });

        // 携带uuid到后台,后台将uuid和socket对象关联,方便通知到哪个网页端
        getUnlimitedQrCode({ "uuid": this.state.uuid }).then((res) => {

            if (res == undefined || res.data == undefined || res.data.data == undefined) {
                console.log("获取二维码失败");
                return null;
            }
            this.setState({
                qrcodeBase64: res.data.data
            });
        }).catch((error) => {
            console.error(error);
        });


    }

后台

// 获取不限制的小程序码接口
func (h *handler) GetUnlimitedQRCode() core.HandlerFunc {

	return func(c core.Context) {

		param := new(RequestQrCodeParam)
		c.ShouldBindJSON(&param)

        // 获取accessToekn
		accesstokenInfo, err := h.getAccessToken()
		if err != nil {
			c.AbortWithError(core.Error(
				http.StatusBadRequest,
				500,
				"获取微信access_token失败").WithError(err),
			)
			return
		}

		qrCodeBytes := postUnlimitedQRCode(accesstokenInfo, param.Uuid)
		// c.ResponseWriter().Write(qrCodeBytes)

		var q = QrcodeRes{Data: qrCodeBytes, Errcode: 0, Errmsg: "success"}

		c.Payload(q)
	}
}

// websocket连接回调函数

var (
	err           error
	server        socket.Server
	SocketManager = make(map[string]*websocket.Conn) // 存储uuid和socket对象的关系
)
func (h *handler) Connect() core.HandlerFunc {
	return func(ctx core.Context) {
		server, err = socket.New(h.logger, h.db, h.cache, ctx.ResponseWriter(), ctx.Request(), nil)
		if err != nil {
			return
		}

		// 保存uuid到map,后续后台主动回调前台,需要根据uuid找到对应的websocket连接
		uuid := ctx.Request().URL.Query().Get("uuid")
		log.Println(uuid)

		conn, err := server.GetConn()
		if err != nil {
			return
		}

		SocketManager[uuid] = conn

		go server.OnMessage()
	}
}


// 登录接口
func (h *handler) Wx_web_login() core.HandlerFunc {

	return func(c core.Context) {
		param := new(RequestWebLoginParam)
		c.ShouldBindJSON(&param)

		

		// 登录操作
		ticketRes, err := registerAndExportToken(h, c, &WxLoginParams{Code: param.Code})
		if err != nil {
			c.AbortWithError(core.Error(
				400,
				500,
				"微信登陆失败").WithError(err),
			)
		}

		log.Print(ticketRes)

		// 登陆成功后,主动调用websocket的接口,返回token
		res := new(webmessage.WebSocketResponse).Success(webmessage.LOGIN_SUCCESS_TYPE, ticketRes)

        // 根据uuid找到对应socket
        socket := webmessage.SocketManager[param.Uuid]
		socket.WriteJSON(res)

		c.Payload(res)

	}

}


小程序端

    // 登录按钮绑定的登录事件
    handleLogin = () => {
        // 处理登录逻辑
        console.log('登录按钮被点击')

        // 获取code
        Taro.login({
            success: (res) => {
                console.log(res)
                if (res.code != '') {
                    // 请求登录操作
                    webWxLogin({ "code": res.code, "uuid": this.state.scene }).then((res) => {
                        console.log(res.data)
                        if (res.data.code == 200 && res.data.type == 20000) {
                            // 登录成功
                            Taro.showToast({
                                title: '登录成功',
                                icon: 'success'
                            })
                            // 跳转首页
                            Taro.switchTab({
                                url: '/pages/home/index'
                            })
                        } else {
                            Taro.showToast({
                                title: '登录失败',
                                icon: 'none'
                            })
                        }
                    }).catch((err) => {
                        console.log(err)
                        Taro.showToast({
                            title: '登录失败',
                            icon: 'none'
                        })
                    })


                } else {
                    Taro.showToast({
                        title: '登录失败',
                        icon: 'none'
                    })
                }
            },
            fail: (err) => {
                console.log(err)
                Taro.showToast({
                    title: '登录失败',
                    icon: 'none'
                })
            }
        })
    }
    // 这段代码是用GitHub Copilot 写的,真的是把所有情况都写出来了😄

😄总结

这次扫码登录前前后后花了我五天的时间(下班后弄得),其中也碰了不少坑,前端二维码不显示、后台不返回二进制数据、nginx代理的https域名网站websocket也要做特殊处理,真的是在里面爬了很久,虽然这个手段不是很正规,但是过程能学到一些知识,实现了自己想要的效果,还是挺满意的,谢谢看到这里,如果哪里有说的有问题,欢迎指正

😃这里打个广告,欢迎大家体验懒熊搜题网站
https://tiku.toolkit.show

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/570231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CH32】| 02——常用外设 | GPIO

系列文章目录 【CH32】| 00——开发环境搭建 【CH32】| 01——新建工程 | 下载 | 运行 |调试 【CH32】| 02——常用外设 | GPIO 失败了也挺可爱,成功了就超帅。 文章目录 前言1. GPIO简介2. IO口的内部结构框图保护二极管上下拉电阻施密特触发器两个MOS管输出寄存器…

chatgpt赋能python:Python加速循环的执行方法详解

Python 加速循环的执行方法详解 Python是一门非常流行的编程语言,它可以在很多领域应用,比如Web开发、数据分析、机器学习等等。然而,Python执行速度较慢,特别是在循环语句中,代码执行效率会大打折扣。在本文中&#…

【基于ROS Melodic环境安装rosserial arduino】

【基于ROS Melodic环境安装rosserial arduino】 1. 简介2. 安装2.1 Ubuntu下的Arduino IDE安装2.2 Ubuntu下rosserial arduino软件安装2.3 安装ros_lib到Arduino IDE开发环境 3. 将ros_lib配置到 Arduino 环境库中4. 使用helloword5. 实验验证6.总结 1. 简介 这个教程展示如何…

Linux系统初始化命令的备忘单,Linux运维工程师收藏!

在管理和维护Linux系统时,有一些常用的命令可以帮助您进行系统初始化和配置。这些命令涵盖了各种任务,包括系统设置、用户管理、软件安装和网络配置等。 本文将为您提供一个Linux系统初始化命令的备忘单,以便在需要时方便查阅和使用。 系统设…

chatgpt赋能python:Python动画制作指南:从入门到精通

Python动画制作指南:从入门到精通 Python作为一种易学易用的编程语言,在数据分析、机器学习等领域已经得到广泛应用。但是你知道吗?Python还可以用来制作动画!本文将为你介绍如何用Python制作动画,从入门到精通&#…

chatgpt赋能python:Python写计算器:从入门到精通

Python写计算器:从入门到精通 简介 计算器无疑是计算机编程中最基本且实用的工具之一。Python 作为一门易于学习且功能强大的编程语言,能够轻松实现计算器的功能。在本文中,我们将介绍如何使用 Python 编写一个简单的计算器。 如何实现&am…

chatgpt赋能python:Python的封装:提高代码的可维护性和可复用性

Python的封装:提高代码的可维护性和可复用性 在软件开发领域中,封装是一种重要的概念。它被用于隐藏程序的实现细节,使得程序的功能变得更加易于使用和维护。在Python编程中,封装是一种被广泛使用的技术,可以帮助你提…

Linux 信号知识点总结

对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号,为 Linux提供了一种处理异步事件的方法。比如,终端用户输入了 ctrlc 来中断程序,会通过信号机制停止一个程序。信号概述 1.信号的名字和编号: 每…

JavaSE_day38(异常分类,自定义异常,File介绍,方法使用,相对路径与绝对路径概念以及注意的点)

1 A.java * 异常的分类: 运行时期异常:RuntimeException的子类就是运行时期异常,在编译时期可以自由选择处理或者不处理 编译时期异常:是Exception的子类,非RuntimeExcpetion的子类,在编译时期必须处理 public c…

注意力机制(一)SE模块(Squeeze-and-Excitation Networks)

Squeeze-and-Excitation Networks(压缩和激励网络) 论文地址:Squeeze-and-Excitation Networks 论文中文版:Squeeze-and-Excitation Networks_中文版 代码地址:GitHub - hujie-frank/SENet: Squeeze-and-Excitation Ne…

chatgpt赋能python:Python内置:优化SEO的利器?

Python 内置:优化SEO的利器? Python是一种广泛使用的高级编程语言,拥有丰富的标准库和第三方库,能够适用于很多领域。其中,Python内置的一些功能,比如字符串操作和网络请求,可以帮助我们进行SE…

web前端综合案例——小兔鲜首页(html+css)

前言:我这里只使用了html和css,js没有使用 项目源代码:https://pan.baidu.com/s/1alnekYEu5F9XwHTW7dO5RA?pwdqjhd 页面效果: 项目准备阶段: 1.准备项目相应的图片素材,设计稿。 2.创建项目: 2.1 项目…

用反射设计通用的实例化对象方案

需求 对象的相关信息存储在javabean.properties文件中,通过读取properties文件中的信息,实例化对象,要求程序不能硬编码,即程序可以通用,针对不同的对象,都可以实例化。仅需修改配置文件,不需要…

网络基础初识

目录 网络发展 时代背景 计算机内部 协议 协议的创立 什么是协议? 网络协议 OSI七层模型 TCP/IP五层(或四层)模型 硬件方面 -- 补充 路由器 协议的分层 网络传输基本流程 1.协议报头 2.局域网 查询自己的MAC地址 局域网通信的原理 跨路由器传递数…

以太网协议详解

文章目录 前言一、MAC地址二、以太网协议1. 以太网数据格式2. MAC地址表 前言 假设有这样一张网络拓扑图: 在拓扑图中有A、B、C三台计算机,并且它们三个是通过中间的路由器连接的。这时候计算机A要向计算机C发送一条数据,那么数据是怎么样到…

nvm教程

介绍 这个东西,是nodejs官网有个链接里面有很多列表,这是其中一个 下载 https://github.com/coreybutler/nvm-windows/releases 安装 安装前,将.npmrc文件删除;文件位置: C:\Users{User}\AppData\Roaming\npm C:\…

chatgpt赋能python:Python单行for:如何简化你的代码

Python单行for:如何简化你的代码 在Python编程中,for循环是必不可少的一部分,它可以用于遍历列表、元组和字典等各种数据类型。而Python单行for则是一种更加简单、更加紧凑的语法形式,可以让你更加高效地遍历和处理数据。 什么是…

STL--mapset(手撕AVL树,红黑树)

1. 关联式容器 在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、 forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 存储的是元素本身。那什么是关…

Yolov5涨点神器:注意力机制---多头上下文集成(Context Aggregation)的广义构建模块,助力小目标检测,暴力涨点

1.数据集性能验证 在crack道路缺陷检测任务中,多头上下文集成(Context Aggregation)的广义构建模块实现暴力涨点mAP50从0.954提升至0.992 🏆🏆🏆🏆🏆🏆Yolov5/Yolov7魔术师🏆🏆🏆🏆🏆🏆 ✨✨✨魔改网络、复现前沿论文,组合优化创新 🚀🚀🚀…

内网渗透(八十三)之安装ADCS证书服务

安装ADCS证书服务 本编文章,我们来讲解安装ADCS证书服务,这里注意一下,因为证书服务特性(不能更改计算机名称、网络参数),因此在部署证书服务器时建议独立部署,ADCS证书服务不能和域控是同一台服务器,这里我用的一台加入域的Server2016搭建 1、以 Enterprise Admins …