微信小程序登陆逻辑封装(附比较完整注释)
发布: 2019-07-13 16:05:56标签: 小程序
一、先看一下如何使用
- login:登陆过返回用户信息,没有登陆过执行登陆逻辑
- loginForce:强制登陆
01import {login, loginForce} from '@/utils/login'0203// 需要登陆才可以执行04async function needLoginFn() {05 await login()06 // todo07}0809// 强制登陆10async function toRrefreshLogin() {11 await loginForce()12 // todo13}14
复制代码二、完整微信小程序登陆逻辑
01import setting from '@/utils/setting' // 用户设置(具体代码在附录)02import authority from '@/utils/authority' // localStorage用户信息保存(具体代码在附录)03import request from '@/utils/request/doRequest' // 类似axios请求方法封装(代码略)04import { redirectLogin } from '@/utils/router' // 重定向登陆,登陆后返回等逻辑(代码略)0506// 并发触发登陆,返回第一次登陆结果07let prevCodeLogin080910/**11 * @description: 检查是否有权限获取用户信息,有的话直接可以直接使用wx.getUserInfo12 */13async function validateSetting() {14 const hasSetting = await setting.has('userInfo')15 if (!hasSetting) {16 // 没有权限的话,清空保存用户信息,重定向登陆17 authority.clear()18 redirectLogin()19 }20 return hasSetting || handleError(new Error('没有获取UserInfo权限'))21}2223/**24 * @description: 检查sessionKey是否过期,过期的话需要重新wx.login获取code登陆25 */26export function validateSession() {27 return new Promise(resolve => {28 wx.checkSession({29 success() {30 resolve(1)31 },32 fail() {33 resolve(0)34 }35 })36 })37}3839/**40 * @description: 通过code登录41 * 用户登陆过:后台可以获取openid或者unionId直接查询到用户信息,实现静默登陆42 * 用户第一次:需要重定向授权页面,点击getUserInfo的按钮授权登陆43 */44export async function codeLogin(force) { // force:是否强制登陆45 // 获取缓存中的用户信息,有id表示已经登陆过46 const cacheUser = authority.get() || {}47 if (!force && cacheUser.id) return cacheUser4849 // isValid:后台code换的session_key是否过期,过期的话不可以解处加密字符串中的用户信息,需要重新登陆50 const isValid = await validateSession() 51 if (force || !isValid) {52 if (prevCodeLogin) return prevCodeLogin53 prevCodeLogin = new Promise((resolve, reject) => {54 wx.login({55 async success({ code }) {56 try {57 // 将code发送给后台,后台可以获取到openid,session_key等58 const res = await request({59 url: '/api/client/v1/auth/session',60 method: 'post',61 data: { code }62 })63 // code获取后台返回的用户信息(登陆过返回完整用户信息,没有登陆过返回token,token用户后台关联当前用户的session_key)64 const { user = {}, token } = res65 user.token = token66 authority.set(user)67 prevCodeLogin = null68 return resolve(user)69 } catch (e) {70 reject(e)71 }72 },73 fail(e) {74 prevCodeLogin = null75 reject(e)76 }77 })78 })7980 return prevCodeLogin81 }82 return cache83}8485/**86 * @description: 解密用户信息或者手机号(encrypted_data, iv)87 * encrypted_data, iv:有获取用户信息权限可以通过getUserInfo获取,否则通过授权按钮获取88 */89export async function toDecode({ encrypted_data, iv }) {90 // 此方法header中默认携带了code登陆返回的token,后台通过token查到session_key,然后解密出用户信息91 const { user, token } = await request({92 url: '/api/client/v1/auth/login',93 method: 'post',94 data: {95 encrypted_data,96 iv97 }98 })99 if (user) {100 user.token = token101 authority.set(user)102 return user103 } else {104 return Promise.reject(new Error('登录decode失败'))105 }106}107108/**109 * @description: getUserInfo 获取加密字符串,传给后台解密出用户信息110 */111export function decodeUserInfo() {112 return new Promise(resolve => {113 wx.getUserInfo({114 lang: 'zh_CN',115 async success(res) {116 const { encryptedData, iv } = res117 const user = await toDecode({118 encrypted_data: encryptedData,119 iv120 })121 resolve(user)122 }123 })124 })125}126127/**128 * @description: 登陆封装129 */130export async function login() {131 // 通过wx.login获取code发给后台132 const user = await codeLogin()133 // 返回id表示静默登陆成功134 if (user.id) {135 return user136 }137 // 判断是否有获取用户信息权限,没有的重定向登陆138 await validateSetting()139 // 有getUserInfo权限才会走下边代码,不需要授权直接使用getUserInfo登陆140 return decodeUserInfo()141}142143/**144 * @description: 强制登录145 */146export async function loginForce() {147 authority.clear()148 await login()149}
复制代码三、附录:所用工具类
authority:简单封装localStorage
01// 储存前缀02const key = 'prefix_key'0304// 储存有效时间05const maxAge = 1000 * 60 * 60 * 24 * 600607export default {08 get() {09 try {10 const user = wx.getStorageSync(key)11 if (!user || user.time + maxAge < new Date().getTime()) return {}12 return user || {}13 } catch (e) {14 return {}15 }16 },17 set(user) {18 if (!user) return null19 user.time = new Date().getTime()20 const oldUser = this.get() || {}21 const newUser = { ...oldUser, ...user }22 wx.setStorageSync(key, newUser)23 return newUser24 },25 clear() {26 const user = this.get() || {}27 wx.clearStorageSync()28 wx.removeStorageSync(key)29 this.set({ user: {} })30 return user31 }32}3334
复制代码setting:用户设置简单封装
01const noop = () => {}0203// 并发查询setting返回同一个结果04let preGetSetting0506// 需要直接点击,不能在异步函数之中(可以使用wx.showModal的success中使用)07export function openSetting(name, callback = noop) {08 wx.getSetting({09 success({ authSetting }) {10 const key = `scope.${name}`11 let success = false12 if (authSetting[key] === false) {13 wx.show14 wx.openSetting({15 success({ authSetting: auth }) {16 if (callback) {17 success = auth[key] !== false18 callback(success)19 }20 }21 })22 } else {23 // 已经有权限24 if (typeof callback === 'function') {25 callback(success)26 }27 }28 }29 })30}3132// 获取用户授权信息33export function getSetting() {34 if (preGetSetting) return preGetSetting35 preGetSetting = new Promise(resolve => {36 wx.getSetting({37 success({ authSetting }) {38 preGetSetting = null39 resolve(authSetting)40 },41 fail(e) {42 preGetSetting = null43 reject(e)44 }45 })46 })47 return preGetSetting48}4950async function hasSetting(name) {51 const setting = await getSetting()52 const key = `scope.${name}` // userLocation、userInfo53 return setting[key]54}5556export default {57 open: openSetting,58 get: getSetting,59 has: hasSetting60}61
复制代码