微信开发踩坑系列之二微信扫码登录

微信开发踩坑系列之二微信扫码登录

  • 1、前言
  • 2、微信扫码登录模式
    • 2.1、基于微信开放平台登录
    • 2.2、基于公众号的扫码登录
  • 3、开发过程
    • 3.1、开发前准备工作
    • 3.2、整体开发流程介绍
    • 3.3、获取微信授权登录二维码
      • 3.3.1 传统方式获取登录二维码
      • 3.3.2 内嵌形式的二维码获取
      • 3.3.3 vue项目中内嵌二维码
    • 3.4、服务端获取数据处理业务
      • 3.4.1 服务端业务描述
      • 3.4.2 代码实现
  • 4、与业务系统整合
    • 4.1、关于redirect_uri参数的配置
      • 4.1.1 方式一:重定向地址为页面
      • 4.2.2 方式二:重定向地址为服务端接口
    • 4.2、整合过程问题及解决方案
  • 5、实用工具
    • 5.1、微信开发环境联调的方式
    • 5.2、微信测试账号系统和调试工具
  • 6、一些思考

1、前言

本文主要是PC的web应用系统(网站应用)整合微信的扫码登录逻辑,即通过微信扫码完成业务系统的登录,也会把常见的几种模式概括性的带一下(当然仅限于自己理解的形式)。
技术栈还是spring+vue+elementUI全家桶。

2、微信扫码登录模式

当前看到的微信扫码登录的有以下两种模式:

  1. 基于微信开放平台的扫码登录模式,官方文档-网站应用微信登录开发指南
  2. 基于公众号的扫码登录模式,这个暂时没实现过,但是这样的场景应该见过,你需要登录某个网站的时候,扫描网站应用的登录二维码之后是直接进入一个公众号,关注公众号之后网站就已经登录成功了。 查阅官方文档之后觉得应该是基于公众号带参数二维码的形式来实现的,移步官方文档,若有理解不对,欢迎指正。

2.1、基于微信开放平台登录

  1. 让微信用户使用微信身份安全登录第三方应用或网站,
  2. 微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),
  3. 通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等

2.2、基于公众号的扫码登录

公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送。
简单理解:就是微信公众平台提供了相应接口,扫码之后不管用户关注与否都会有对应的回调通知给开发者,开发者可以此来做对应的业务开发。
本文是以微信开发平台的网站应用微信登录的方式实现的

3、开发过程

3.1、开发前准备工作

微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。微信开发踩坑系列之二微信扫码登录_第1张图片
微信开发踩坑系列之二微信扫码登录_第2张图片

3.2、整体开发流程介绍

  1. 页面中嵌入/打开微信官网提供的链接授权链接,按照要求配置相应的参数即可生成微信登录的二维码。
  2. 用户扫码确认授权之后会跳转至已配置的重定向URL,并带上code参数。
  3. 业务系统获取code参数,访问微信授权接口获取access_token(接口调用凭证)。
  4. 之后就可以根据access_token调用微信的相关接口,此处只能调用获取用户基本信息的接口。
  5. 获取到用户信息之后在业务系统实现对应的业务逻辑。

3.3、获取微信授权登录二维码

根据官方文档的说法,获取显示二维码也有两种方式:
1、直接打开微信官方提供的链接,以新页面的形式。
2、内嵌到页面中显示,一般为了业务系统整体UI的协调和好看,都会采用此种方式。
用户扫码授权通过之后,主要是为了获取到code参数,以便后面的接口调用

3.3.1 传统方式获取登录二维码

通过访问以下链接,配置好对应的参数,即可获取到二维码:

https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中比较重要的两个参数:
redirect_uri---->授权成功后的重定向地址,会带上code参数,如何配置后面会说说个人理解。
state---->访问重定向地址时会返回,可用于做接口校验。
正常操作的正确返回:redirect_uri?code=CODE&state=STATE

3.3.2 内嵌形式的二维码获取

需要引入微信官方提供的js文件,在js中按照要求实例对象即可。通过查看微信官方提供的js文件源码可知,其实就是以iframe的形式访问方式一的地址。部分源码分析如下(若需要修改二维码的属性可直接修改js):

var d = b.createElement("iframe"),
	e = "https://open.weixin.qq.com/connect/qrconnect?appid=" + a.appid + "&scope=" + a.scope + "&redirect_uri=" + a.redirect_uri + "&state=" + a.state + "&login_type=jssdk&self_redirect=" + c + '&styletype=' + (a.styletype || '') + '&sizetype=' + (a.sizetype || '') + '&bgcolor=' + (a.bgcolor || '') + '&rst=' + (a.rst || '');
	e += a.style ? "&style=" + a.style: "",
	e += a.href ? "&href=" + a.href: "",
d.src = e,

3.3.3 vue项目中内嵌二维码

有现成的vue插件可以直接使用,vue-wxlogin组件首页地址,具体代码结构如下,其实也是构建了一个iframe的形式显示二维码,后面如何与业务系统整合基于此方式说明

<template>
  <div>
    <iframe scrolling="no" width="300" height="400" frameBorder="0" allowTransparency="true" :src="setSrc"></iframe>
  </div>
</template>
<script>
export default {
  name:'wxlogin',
  data () {
    return {
      src: 'https://open.weixin.qq.com/connect/qrconnect?appid=wxe1f5def243e0390b&scope=snsapi_login&redirect_uri=https://abstest.tenpay.com/abs/author/callBack.do&state=0001&login_type=jssdk&self_redirect=default&style=black&href=./wx.css',
    }
  },
  computed : {
      setSrc () {
          var _url = 'https://open.weixin.qq.com/connect/qrconnect?appid='+ this.appid
              + '&scope=' + this.scope
              + '&redirect_uri='  + this.redirect_uri
              + '&state=' + this.state
              + '&login_type=' + this.login_type
              + '&self_redirect=' + this.self_redirect
              + '&style=' + this.theme
              + '&href=' + this.href;
          return _url;
      },
  },
  props:{
      //应用唯一标识,在微信开放平台提交应用审核通过后获得
      appid : String,
      //应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
      scope : String,
      //重定向地址,需要进行UrlEncode
      redirect_uri : String,
      //用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
      state : {
          type : String,
          default: ''
      },
      //提供"black"、"white"可选,默认为黑色文字描述。详见文档底部FAQ
      theme : {
          type : String,
          default: 'black'
      },
      // 自定义样式链接,第三方可根据实际需求覆盖默认样式。详见文档底部FAQ
      href : {
          type : String,
          default: ''
      },
      // true:手机点击确认登录后可以在 iframe 内跳转到 redirect_uri,false:手机点击确认登录后可以在 top window 跳转到 redirect_uri。默认为 false。
      self_redirect : {
          type : Boolean,
          default: false
      },
      // sdk的扩展字符串,但是在这里就默认了jssdk,暂时不建议修改
      login_type : {
          type : String,
          default: 'jssdk'
      },
},
}
</script>

在文件中使用:

<template>
    <div>
        <wxlogin :appid="me_appid" :scope="me_scope" :redirect_uri="me_redirect_uri" :self_redirect="true"></wxlogin>
    </div>
</template>
<script>
import wxlogin from '../components/vue-wxlogin.vue';
export default {
	components:{wxlogin},
	data(){
	return{
		me_appid:'',
        me_scope:'',
        me_redirect_uri:'',
	},
	mmounted(){
	//……do something
	}
}
}

此时,页面中已经可以正常显示微信授权登录的二维码信息了。用户可扫码确认授权或者不授权。

3.4、服务端获取数据处理业务

3.4.1 服务端业务描述

不管采用哪种redirect_uri的配置,服务端都需要接收code参数,然后服务端主要做了三个事情:
1、根据code换取access_token(接口调用凭证)

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
会返回用户的openid和access_token两个关键参数

2、使用access_token和openid获取用户信息,

http请求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
具体响应的用户参数可查看授权后接口调用的文档说明。

3、根据用户信息,做对应的业务处理(比如:查询业务系统是否有对应的用户)。

3.4.2 代码实现

当然也可以再服务端获取state参数,做一下接口检验,保障传输的正确性

@RequestMapping(value = "wx_login",method=RequestMethod.GET)
public String redirectUri(@RequestParam(name = "code", required = false) String code) throws ClientProtocolException, IOException {
	//获取接口调用凭证
	String AccessToken_url = WxLoginParams.WX_ACCESS_TOKEN+"?appid="+WxLoginParams.WX_OPEN_APPID+"&secret="+WxLoginParams.WX_OPEN_APPSECRET+"&code="+code+"&grant_type=authorization_code";
	//HttpClientUtils为服务端访问https接口的工具类
	String access_token_str = HttpClientUtils.doGet(AccessToken_url);
	System.out.println(access_token_str);
	//格式化获取凭证接口响应值。
	JSONObject jo_token = JSON.parseObject(access_token_str);
	String tocken = jo_token.getString("access_token");
	String openid = jo_token.getString("openid");
	//根据接口凭证获取用户信息。
	String wx_userinfo_url = WxLoginParams.WX_USERINFO_URL+"?access_token="+tocken+"&openid="+openid;
	String wx_userinfo = HttpClientUtils.doGet(wx_userinfo_url);
	//格式化用户信息
	JSONObject jo_user = JSON.parseObject(wx_userinfo);
	//可根据格式化的用户信息来做相应的业务逻辑处理。
	//......do something
	return wx_userinfo;
}

4、与业务系统整合

要和业务系统整合,还得看具体的业务场景和使用的开发框架,本文暂时还是以我项目的场景记录一下。
其中比较关键的是关于redirect_uri的配置,决定着如何整合。

4.1、关于redirect_uri参数的配置

首先代码中的redirect_uri配置,必须是在开放平台中授权回调域配置下的地址,否则无法生成二维码信息,其次该地址必须可以外网访问到,否则会提示链接无效。
微信开发踩坑系列之二微信扫码登录_第3张图片
配置redirect_uri的过程中有两种思路,且都做了尝试,是没有问题的,但具体采用哪种就要结合具体的业务场景及所采用的技术框架了:
1、配置为具体的页面,授权登录成功后,原有登录页会重定向到这个页面,页面获取到url中的参数,带参数请求服务端,做后续的逻辑处理。
2、配置为后台的接口地址,授权成功后,服务端获取code,做后续逻辑处理(但会有个问题,前端要如何知道授权成功了?)。

4.1.1 方式一:重定向地址为页面

我项目中开发目前使用的是第一种,具体实现思路如下:
因为是在登录页做微信扫码登录,所以我的重定向地址还是指向到登录页面,只不过在钩子函数mounted()中判断url中是否含code,存在即访问服务端做相应的逻辑处理,之后前端再做页面跳转。

mounted(){
        const url = window.location.href;
        console.log(url);
        if(url.indexOf("code")!=-1){
            console.log("用户已扫码,进行后端登录逻辑确认。")
            let query = url.split("?")[1];
            //js中获取get请求的参数。
            let searchParams = new URLSearchParams(query);
            //带code参数访问服务端接口。
            this.$api.get("服务端接口",{code:searchParams.get("code")},res =>{
                //用户登录成功的业务逻辑
                this.wx_userinfo = res.data;
                this.is_qr_show = false;
                this.$route.push({name:"Test"})
            });
        }
    }

根据服务端返回的状态值,页面做相应的逻辑处理。
:mounted函数中获取当前的地址栏函数,需要用window.location.href来获取,一开始打算是使用路由守卫函数来监听,发现重定向进入页面后并不会触发监听。

4.2.2 方式二:重定向地址为服务端接口

服务端的接收方式和处理逻辑与方式一的一致,唯一不同的是在服务端进行页面重定向,并把用户id传到页面,页面中做相应的处理(比如:用户信息获取),以下是一个测试服务端重定向的示例:

@GetMapping("test_redir")
public String test(HttpServletResponse response) {
	System.out.println(123);
	return "redirect:http://localhost:8080/#/test2?id=12312";
}

事实证明,回调test_redir时,页面会重定向至指定的页面。
可能存在的问题?
采用的是前后端分离的模式,这样回调可能会存在传值的问题,若是以前使用springMVC的框架,则应该是用这种方式。
另外:网上看到还有一种实现方法是服务端不做页面重定向,而是在前端进行轮询判断用户是否登录成功。

4.2、整合过程问题及解决方案

使用方式一,由于使用的vue框架开发,vue路由默认使用的是hash模式,访问页面过程中url中会有#,此时配置到redirect_uri中时,#后面的内容会被清掉(微信自动处理),所以配置重定向地址时不能有#
解决思路:
1、修改vue的路由模式为“history”,路径访问就不会有#。
2、将需要重定向的页面设置为根路由(一般情况下根路由就是登录页面),就可以在该页面做相应的逻辑处理。

5、实用工具

5.1、微信开发环境联调的方式

由于微信开发的很多回调和通知都需要互联网可以访问到的服务,所以本地开发调试的时候就需要本地服务可以映射到互联网,即微信回调可以访问到的服务。

5.2、微信测试账号系统和调试工具

微信公众平台测试账号系统
微信公众平台接口调试工具
在账号申请或者审核阶段,就可以使用沙箱账号进行开发测试。

6、一些思考

按照官方文档,也可以实现基础的功能,但是要和已有的业务系统结合,嵌入功能后依然流畅就需要动脑经怎么去优化了,自己整理一遍,对微信授权登录的过程会更清晰,若有对应场景的开发,可能还得依托官方文档来实现,但是思考问题的深度就不一样了。

你可能感兴趣的:(微信开发,java,vue.js,前端)