• 前端Vue+后端Django实现微信登录


    一直想做网站的微信登录,虽然自己做用户系统也可以,但是我感觉每次创建账号非常麻烦,而且还要记密码,虽然浏览器也能够帮忙记住密码,但是也感觉不安全。

    如果网站都统一用微信登录,就不用那么麻烦了,也不用注册账号,直接扫码即可。

    准备工作:前端Vue+后端Django项目创建以及自动部署流程,网站接入微信登录需要域名备案的哦,所以必须在绑定域名的公网上测试,或者本地做内网穿透。

    微信开放平台申请网站

    微信开放平台链接

    按照要求创建一个网站应用,需要准备一个网站信息登记表,这个比较麻烦,需要域名备案信息以及盖章。

    在这里插入图片描述
    创建申请之后大概需要1-2个工作日审核,通过之后即可查看AppID和AppSecret。

    在这里插入图片描述
    在这里插入图片描述
    注意设置开发信息的授权回调域,用户使用微信帐号登录后,只能回调至该域名下的页面,注意不要加上htpp。

    在这里插入图片描述

    微信登录流程

    获得相应的 AppID 和AppSecret,申请微信登录且通过审核后,可开始接入流程。

    微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。 微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有 server 端的应用授权。该模式整体流程为:

    1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据 code 参数;
    2. 通过 code 参数加上 AppID 和AppSecret等,通过 API 换取access_token;
    3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

    获取access_token时序图:
    在这里插入图片描述

    前端Vue开发

    两种登录方式

    微信的扫码登录由两种方式:

    1. 跳转到微信提供的页面进行扫码登录,比如京东。在这里插入图片描述

    2. 把微信登录二维码嵌入到网页中进行登录
      在这里插入图片描述

    我个人觉得第二种方式更简洁一些,而且不用做一些跳转,用户体验更好。第二种方式还支持自定义一些样式,例如二维码的大小、是否有标题等。

    后面都是以实现第二种方式为目标进行开发。

    引入wxLogin.js文件

    网站将微信登录二维码内嵌到自己页面中,用户使用微信扫码授权后通过JS将code返回给网站。

    JS微信登录主要用途:网站希望用户在网站内就能完成登录,无需跳转到微信域下登录后再返回,提升微信登录的流畅性与成功率。

    <script type="text/javascript" src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
    
    • 1

    index.html文件中引入该文件。

    在这里插入图片描述

    登录页面请求二维码

    <template>
      <div>
        <div id="wx_login_container" style="height: 300px"></div>
      </div>
    </template>
    <script>
    export default {
      name: "login",
      data() {
        return {}
      },
      mounted() {
        this.get_wx_qrcode();
      },
      methods: {
        get_wx_qrcode() {
          let wx_login = new WxLogin({
            id: "wx_login_container",
            appid: "wx53cf447461989356",
            scope: "snsapi_login",
            redirect_uri: encodeURIComponent("http://www.template.matrix-studio.top/#/login"),
            state: Math.ceil(Math.random() * 100),
            style: "black",
            href: "",
            self_redirect: false,
          });
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    参数说明:

    参数是否必须说明
    self_redirecttrue:手机点击确认登录后可以在 iframe 内跳转到 redirect_uri,false:手机点击确认登录后可以在 top window 跳转到 redirect_uri。默认为 false。
    id第三方页面显示二维码的容器id
    appid应用唯一标识,在微信开放平台提交应用审核通过后获得
    scope应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
    redirect_uri重定向地址,需要进行UrlEncode
    state用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止 csrf 攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加 session 进行校验
    style提供"black"、"white"可选,默认为黑色文字描述。
    href自定义样式链接,第三方可根据实际需求覆盖默认样式。

    在这里插入图片描述

    用户允许授权后,将会重定向到redirect_uri的网址上,并且带上 code 和state参数。

    可以发现我们登录页面的URL和redirect_uri是一样的,相当于重定向到了自己然后添加了两个参数。所以我们可以写一个setInterval,每隔一秒检查当前URL中是否包含code参数,如果有的话将code发送给后端,然后后端拿着code再去请求微信API即可拿到用户信息。

    前端项目代码:https://github.com/Matrix-King-Studio/web_template_0_frontend

    后端Django开发

    前端、微信、后端交互时序图

    在这里插入图片描述

    后端登录逻辑

    所以后端要做的事情也相对比较简单,只需要拿到code然后请求微信相应的接口即可。

    核心代码:

    @api_view(["GET"])
    def wx_login(request):
    	# 微信扫码登录接口
    	params = {
    		"appid": settings.WeiXinWebAppID,
    		"secret": settings.WeiXinWebAppSecret,
    		"code": request.GET.get("code"),
    		"grant_type": "authorization_code"
    	}
    	res = requests.get("https://api.weixin.qq.com/sns/oauth2/access_token", params=params)
    	res = res.json()
    	access_token = res["access_token"]
    	openid = res["openid"]
    	# 获取用户信息
    	params = {
    		"access_token": access_token,
    		"openid": openid,
    	}
    	res = requests.get("https://api.weixin.qq.com/sns/userinfo", params=params)
    	res = res.json()
    	# 判断用户是否存在
    	account = Account.objects.filter(openid=openid).first()
    	if not account:
    		# 如果用户不存在,则创建用户
    		account = Account.objects.create(
    			openid=openid,
    			unionId=res["unionid"],
    			nickname=res["nickname"],
    			headImgUrl=res["headimgurl"]
    		)
    	# 根据用户信息生成JWT token
    	jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    	jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    	payload = jwt_payload_handler(account)
    	token = jwt_encode_handler(payload)
    	# 返回用户信息 + token
    	return Response({
    		"token": token,
    		"account": {
    			"openid": account.openid,
    			"nickname": account.nickname,
    			"headImgUrl": account.headImgUrl
    		}
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    后端项目代码:https://github.com/Matrix-King-Studio/web_template_0_backend


    大部分的工作其实都是在前期准备,包括域名备案、微信开发平台申请网站应用、开发者资质认证等等,实际敲代码的时间并没有很多。


    参考文献:

    1. 微信官方文档 网站应用微信登录开发指南
    2. 微信官方文档 返回码说明
  • 相关阅读:
    反序列化漏洞(4), phar文件反序列化, 漏洞实验, 漏洞利用
    YBTOJ 期望分数【第31章 期望问题】
    Docker 容器监控之CAdvisor+InfluxDB+Granfana
    给使用docker安装的ES和Kibana设置账号密码
    系统迁移从CentOS7.9到Rocky8.9
    php jquery ajax 无法传递POST值的问题
    面试中的最常被问到的两种锁
    Android 开发小贴士
    leetCode热题100——两数之和(python)
    obsidian云同步方案记录
  • 原文地址:https://blog.csdn.net/weixin_43336281/article/details/125819173