使用 Abp.Zero 搭建第三方登录模块(四):微信小程序开发

简短回顾一下微信小程序端的流程:

  1. 用户通过扫码进入小程序的鉴权页面,更新状态到ACCESSED已扫码
  2. 用户点击确认授权,微信通过wx.login()接口获取第三方登录的必要信息:Code登录凭证。

微信小程序主要为用户授权行为提供交互功能,用户在扫码之后,提供一个交互UI,如下:


使用 Abp.Zero 搭建第三方登录模块(二):服务端开发 - 林晓lx - 博客园 (cnblogs.com)中介绍了服务端已经搭建的接口,这次我们将调用Access和Authenticate,分别调用来完成已扫码和已授权状态的更新。

项目搭建

 首先使用vue-cli创建一个web项目,命名为mp-weixin

vue create -p dcloudio/uni-preset-vue mp-weixin

 在Pages下创建login/index.vue页面,作为登录授权页

目录结构如下:


pages.json:

{
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/index/index",
			"style": {
				"navigationBarTitleText": "uni-app"
			}
		},
		{
			"path": "pages/login/index",
			"style": {
				"navigationBarTitleText": "授权页"
			}
		}
	],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	}
}

 login目录下新建ajaxRequire.ts, 创建request对象,这一对象将利用uni-axios-ts库发送ajax请求

import axios from 'uni-axios-ts'
//发送网络请求
export const request = async (url: string, methods, data: any, onProgress?: (e) => void, cancelToken?) => {
    let token = null
    let timeout = 3000;
    if (cancelToken) {
        token = cancelToken.token
        timeout = 0;
    }
    const service = axios.create()


    service.interceptors.request.use(
        (config) => {
            config.header['Content-Type'] = "application/json"
            return config
        },
        (error) => {
            Promise.reject(error)
        }
    )


    const re = await service.request({
        headers: { 'Content-Type': 'multipart/form-data' },
        url: url,
        method: methods,
        data: data,
        cancelToken: token,
        timeout: timeout,
        onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
            if (progressEvent.lengthComputable) {
                if (onProgress) {
                    onProgress(progressEvent);
                }
            }
        },
    })
    return re as any;
}

///获得取消令牌
export const getCancelToken = () => {
    const source = axios.CancelToken.source();
    return source;
}

index.vue中创建loginExternalForms作为参数传输对象

export default {
  data() {
    return {
      loginExternalForms: {
        WeChat: {
          token: "",
          providerAccessCode: "",
        },
      }
    };
  }
}

onLoad函数中,option存有扫描小程序码中的scene参数,将scene参数赋值给token变量

 onLoad(option) {
    this.loginExternalForms.WeChat.token = option.scene;
    this.start();
  },

start中我们调用Access接口,更改状态至ACCESSED(已扫码) ,若返回成功,则提示点用户点击确认授权,若返回的结果异常"WechatMiniProgramLoginInvalidToken"时,表明此时小程序码已过期,需在网页端更新小程序码。

    async start() {
      var currentForms = this.loginExternalForms["WeChat"];
      this.loading = true;
      await request(`${this.prefix}/MiniProgram/Access`, "post", currentForms)
        .then((re) => {
          this.successMessage("您已扫描二维码,请点击确认登录以完成");
        })
        .catch((c) => {
          var err = c.response?.data?.error?.message;
          if (err != null) {
            if (err == "WechatMiniProgramLoginInvalidToken") {
              this.isInvalid = true;
            } else {
              this.errorMessage(c.err);
            }
          }
        })
        .finally(() => {
          setTimeout(() => {
            this.loading = false;
          }, 1.5 * 1000);
        });
    },

Prefix是你的服务地址前缀

prefix: "https://localhost:44311/api/services/app"

在Html中,我们创建授权登录与取消按钮,仅当isInvalid 为true时可以点击授权

      <button
        @click="handleWxLogin"
        :disabled="isInvalid || loading"
        class="sub-btn"
      >
        授权登录
      </button>

      <button @click="cancelWxLogin" :disabled="loading" class="sub-btn">
        取消
      </button>

创建 handleExternalLogin用于处理用户点击授权登录后的逻辑,调用Authenticate接口,更新状态至AUTHORIZED(已授权)在此之前需要调用uni.login获取小程序登录凭证code。

有关uni.login函数,请参考官方文档uni.login(OBJECT) | uni-app官网 (dcloud.io)

uniapp支持多种小程序,为了保留一定的扩展能力,handleExternalLogin函数中我们保留参数authProvider,已实现的微信小程序登录handleWxLogin函数调用时传递参数"WeChat",

    async handleExternalLogin(authProvider) {
      var currentForms = this.loginExternalForms[authProvider];
      this.loading = true;
      await request(
        `${this.prefix}/MiniProgram/Authenticate`,
        "post",
        currentForms
      )
        .then((re) => {
          uni.redirectTo({
            url: "/pages/index/index",
          });
        })
        .catch((c) => {
          var err = c.response?.data?.error?.message;
          if (err != null) {
            if (err == "WechatMiniProgramLoginInvalidToken") {
              this.isInvalid = true;
            } else {
              this.errorMessage(c.err);
            }
          }
          setTimeout(() => {
            this.loading = false;
          }, 1.5 * 1000);
        });
    },


   async handleWxLogin() {
      const that = this;
      uni.login({
        provider: "weixin",
        success: (loginRes) => {
          that.loginExternalForms.WeChat.providerAccessCode = loginRes.code;
          that.handleExternalLogin("WeChat");
        },
      });
    },

创建取消登录函数

    cancelWxLogin() {
      uni.redirectTo({
        url: "/pages/index/index",
      });
    },

执行成功通知函数

    successMessage(value = "执行成功") {
      uni.showToast({
        title: value,
        icon: "success",
        duration: 1.5 * 1000,
      });
    },

接下来简单编写一个界面,

界面将清晰的反映isInvalid与loading状态时对应的UI交互:

正常


小程序码过期 


整体测试

模拟器测试

打开网页后,将图像另存为

 

 在微信小程序调试工具,“通过二维码编译”


 等待手机界面显示授权页面后点击“授权登录”:

 

 GetCurrentUser接口返回正确数据,并显示于web页面之上

 

 

至此完成了小程序端的开发工作

项目地址

jevonsflash/abp-mp-auth (github.com)

 

结束语

小程序登录具有一定的扩展性,虽然通篇介绍微信小程序登录,但登录鉴权作为小程序抽象功能,uniapp集成了各个平台(微信、支付宝、百度、字节跳动小程序)的登录接口,通过uni.login可以获取相应平台的code

posted @ 2022-07-19 17:12  林晓lx  阅读(209)  评论(0编辑  收藏  举报