当前位置: 首页 > news >正文

微信全局登录设计与实现

前言

最近对于工程的微信登录逻辑进行了重构,进行了如下思考。

工程简介

工程是一个后台管理系统,使用vue框架客户端渲染,其中有一个模块运行在手机端,并且涉及到微信登录,在早期的设计中,对于微信浏览器内的登录是这样处理的:

  • 微信浏览器或者普通浏览器打开分享的链接
  • 如果是非登录状态,那么在请求接口的过程中因为网络请求拦截器的作用会将页面重定向到登录页
  • 在登录页进行判断,如果是普通浏览器则手动登录,微信浏览器则自动登录
  • 登录成功后会重定向到之前的页面

为什么之前会这样处理呢,原因在于,此工程的登录流程会设计到多个状态的查询与处理,例如:

  • 微信登录后检查用户信息,如果用户没有绑定手机号,那么弹出绑定手机号的模态框进行绑定手机号
  • 手机号码登录后,如果用户没有绑定微信,那么弹出微信绑定的模态框,要求用户绑定微信

这样过于复杂的一系列需求,不太利于做成全局的处理,当时也没想到好的解决方案,但是这样来回的跳转,对于用户体验不够友好,近期对项目进行重构时,决心改善这一问题。

解决方案

提炼公共逻辑

对于微信登录,获取微信授权链接的跳转以及微信返回code的处理是一个通用的逻辑,对此做了如下封装

export function wxLogin(callback) {
    const code = getQueryString(window.location.href, 'code')
    if (!code) {
        window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${process.env.WX_APP_ID}&response_type=code&scope=snsapi_userinfo&state=onfuckweixin&redirect_uri=${escape(`${window.location.href}`)}#wechat_redirect`
    } else {
        axios.post(IP + '/login/wxauth', {
            code: code
        }).then(data => {
            if (!data.phone_bind) {
                bindPhone()
            } else {
                location.href = replaceQueryString('code', '')
                callback()
            }
        }).catch(e => {
            vue.$notify.error({
                title: '错误',
                message: '微信登陆失败'
            })
        })
    }

    function bindPhone() {
        const comp = new BindComponent().$mount()
        document.body.appendChild(comp.$el)
        comp.open({
            type: 'phone',
            success: () => {
                location.href = replaceQueryString('code', '')
                window.location.reload()
            }
        })
    }
}
复制代码

大致的意思是,进行微信登录时,先判断url是否已经有code,有code说明已经获得授权,那么直接将code发送给服务器进行登录就好,如果没有code信息,那么说明是未授权,则跳转微信授权地址,获取授权,值得一题的是这一段逻辑:

import Vue from 'vue'
import Bind from '@/components/bind/bind'
const BindComponent = Vue.extend(Bind)

...

function bindPhone() {
    const comp = new BindComponent().$mount()
    document.body.appendChild(comp.$el)
    comp.open({
        type: 'phone',
        success: () => {
            location.href = replaceQueryString('code', '')
            window.location.reload()
        }
    })
}
复制代码

因为之前在编写绑定相关逻辑时有先见之明,提前封装了绑定的组件,所以这里可以很方便的进行调用,当服务器返回该用户没有绑定手机的信息时,则实例化绑定组件并将dom渲染到页面(这种做法是UI组件库常用的逻辑)绑定成功后,删除url中的code字段,并且刷新页面,为什么要刷新页面呢?看如下代码:

//main.js

const bootstrap = function() {
    new Vue({
        router,
        store,
        render: h => h(App)
    }).$mount('#app')
}

if (isWX() && getQueryString(window.location.href, 'code')) {
    wxLogin(bootstrap)
} else {
    bootstrap()
}
复制代码

在工程的入口页面对于根vue组件的实例化之前进行了一次判断:

如果是微信浏览器,并且url中附带了code信息,那么进入微信登录的逻辑,否则进行页面渲染

如果登录成功且已经绑定过手机,执行回调函数也就是实例化根vue:

else {
    location.href = replaceQueryString('code', '')
    callback()
}
复制代码

其实这里有点递归的意思,需要各位自行理解,不做详细说明。

既然入口文件只有在获取到code的前提下才进行微信登录,那么如果当前url没有code并且需要使用微信登录该怎么办?解决方案如下:

repInterceptor: [function(response) {
    try {
        if (response.data.success) {
            return response.data.data
        } else if ([401, 403].includes(response.data.error_code)) {
            if (timer) {
                clearTimeout(timer)
            }
            timer = setTimeout(() => {
                loginCheck(response.data.error_text)
            }, 500)
        } 
        return Promise.reject(response.data)
    } catch (e) {
        return Promise.reject(e)
    }
}, function(e) {
    // Do something with response error
    return Promise.reject({ error_text: '网络错误: ' + e })
}]
复制代码

如上是此工程的网络拦截器,如果返回401或者403说明用户在未登录的前提下请求了限制接口,那么会执行 loginCheck,而在loginCheck函数中有这样一段逻辑:

if (isWX()) {
    wxLogin()
}
复制代码

一切又回到了宇宙的中心 wxLogin ==~

相关文章:

  • 朝鲜APT集团Lazarus通过KEYMARBLE Backdoor瞄准俄罗斯组织
  • Less 日常用法
  • 手机端车牌号码键盘的vue组件
  • 回归生活:清理微信公众号
  • Cisco Nexus 系列交换机NX-OS升级
  • React开发实战
  • 工作中总结前端开发流程--vue项目
  • Java各种IO流的总结
  • MySQL-事务管理(基础)
  • Vultr 教程目录
  • Navicat
  • HTML-表单
  • mahout的数据文件格式
  • 微信小程序开发总结
  • 编码占用字节数
  • 0x05 Python数据分析,Anaconda八斩刀
  • CentOS 7 防火墙操作
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • Laravel核心解读--Facades
  • Python socket服务器端、客户端传送信息
  • SpiderData 2019年2月16日 DApp数据排行榜
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 闭包--闭包之tab栏切换(四)
  • 诡异!React stopPropagation失灵
  • 前端面试之CSS3新特性
  • 使用权重正则化较少模型过拟合
  • 事件委托的小应用
  • 延迟脚本的方式
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 用mpvue开发微信小程序
  • AI算硅基生命吗,为什么?
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (31)对象的克隆
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (实战篇)如何缓存数据
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)基于IDEA的JAVA基础1
  • (转)Oracle存储过程编写经验和优化措施
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • .Net MVC4 上传大文件,并保存表单
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .net的socket示例
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @JsonSerialize注解的使用
  • [30期] 我的学习方法
  • [Angular 基础] - 指令(directives)
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)
  • [C++]命名空间等——喵喵要吃C嘎嘎
  • [C++提高编程](三):STL初识
  • [corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape
  • [CUDA手搓]从零开始用C++ CUDA搭建一个卷积神经网络(LeNet),了解神经网络各个层背后算法原理