前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小程序的登录与静默续期

小程序的登录与静默续期

作者头像
ITer.996
发布2019-08-28 10:45:25
2.3K0
发布2019-08-28 10:45:25
举报
文章被收录于专栏:PHPer技术栈PHPer技术栈

每一个有数据交互的小程序,都会涉及到登录、token 等问题,openid 又是什么呢?怎么使用静默续期,来提升用户体验呢?

小程序登录


登录时序

一切的一切,都要从这么一张小程序登录时序图说起:

通常情况下,我们的小程序都会有业务身份,如何将微信帐号和业务身份关联起来呢?这个时候我们需要上图的步骤:

小程序调用wx.login()获取临时登录凭证code。

小程序将code传到开发者服务器。

开发者服务器以code换取用户唯一标识openid和会话密钥session_key。

开发者服务器可绑定微信用户身份id和业务用户身份。

开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。

相关数据或参数

上面的登录时序中,我们会涉及到一些数据和参数,先来了解下它们都是用来做啥的。

临时登录凭证 code 在小程序中调用wx.login(),能拿到一个code作为用户登录凭证(有效期五分钟)。在开发者服务器后台,开发者可使用code换取openidsession_key等信息(code只能使用一次)。

code的设计,主要用于防止黑客使用穷举等方式把业务侧个人信息数据全拉走。

AppId 与 AppSecret 为了确保拿code过来换取身份信息的人就是对应的小程序开发者,到微信服务器的请求要同时带上AppIdAppSecret

session_key 会话密钥session_key是对用户数据进行加密签名的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。

设计session_key主要是为了节省流程消耗,如果每次都通过小程序前端wx.login()生成微信登录凭证code去微信服务器请求信息,步骤太多会造成整体耗时比较严重。

使用接口wx.checkSession()可以校验session_key是否有效。用户越频繁使用小程序,session_key有效期越长。session_key失效时,可以通过重新执行登录流程获取有效的session_key

openid openid是微信用户id,可以用这个id来区分不同的微信用户。 微信针对不同的用户在不同的应用下都有唯一的一个openid, 但是要想确定用户是不是同一个用户,就需要靠unionid来区分。

unionid 如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性。同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。

加锁的登录

在某些情况下,我们或许多个地方会同时触发登录逻辑(如多个接口同时拉取,发现登录态过期的情况)。一般来说,我们会简单地给请求加个锁来解决:

1.使用isLogining来标志是否请求中

2.方法返回 Promise,登录态过期时静默续期后重新发起

3.使用sessionId来记录业务侧的登录态

代码语言:javascript
复制
// session 参数 key(后台吐回)
        export const SESSION_KEY = 'sessionId';
        let isLogining = false;
        export function doLogin() {
            return new Promise((resolve, reject) => {
                const session = wx.getStorageSync(SESSION_KEY);
                if (session) {
// 缓存中有 session
                    resolve();
                } else if (isLogining) {
// 正在登录中,请求轮询稍后,避免重复调用登录接口
                    setTimeout(() => {
                        doLogin()
                            .then(res => {
                                resolve(res);
                            })
                            .catch(err => {
                                reject(err);
                            });
                    }, 500);
                } else {
                    isLogining = true;
                    wx.login({
                        success: (res) => {
                            if (res.code) {
                                const reqData: ILoginRequest = {
                                    code: res.code
                                }
                                wx.request({
                                    url: API.login,
                                    data: reqData,
// method: "POST",
                                    success: (resp) => {
                                        const data = resp.data;
                                        isLogining = false;
// 保存登录态
                                        if (data.return_code === 0) {
                                            wx.setStorageSync(SESSION_KEY, data[SESSION_KEY]);
                                            resolve();
                                        } else {
                                            reject(data.return_msg);
                                        }
                                    },
                                    fail: err => {
// 登录失败,解除锁,防止死锁
                                        isLogining = false;
                                        reject(err);
                                    }
                                });
                            } else {
// 登录失败,解除锁,防止死锁
                                isLogining = false;
                                reject();
                            }
                        },
                        fail: (err) => {
// 登录失败,解除锁,防止死锁
                            isLogining = false;
                            reject(err);
                        }
                    });
                }
            });
        }

登录态静默续期的实现

checkSession

前面也提到,微信不会把session_key的有效期告知开发者,因此需要使用接口wx.checkSession()来校验session_key是否有效。

这里我们:

1.使用isCheckingSession来标志是否查询中。

2.返回 Promise。

3.使用isSessionFresh来标志session_key是否有效

代码语言:javascript
复制
import {doLogin} from "./doLogin";
        import {SESSION_KEY} from "./doLogin";
        let isCheckingSession = false;
        let isSessionFresh = false;
        export function checkSession(): Promise<string> {
            return new Promise((resolve, reject) => {
                const session = wx.getStorageSync(SESSION_KEY);
                if (isCheckingSession) {
                    setTimeout(() => {
                        checkSession().then(res => {
                            resolve(res);
                        }).catch(err => {
                            reject(err);
                        });
                    }, 500);
                } else if (!isSessionFresh && session) {
                    isCheckingSession = true;
                    wx.checkSession({
                        success: () => {
                            // session_key 未过期,并且在本生命周期一直有效
                            isSessionFresh = true;
                            resolve();
                        }, fail: () => {
                            // session_key 已经失效,需要重新执行登录流程
                            wx.removeStorage({
                                key: "skey", complete: () => {
                                    doLogin().then(() => {
                                        resolve();
                                    }).catch(err => {
                                        reject(err);
                                    });
                                }
                            });
                        }, complete: () => {
                            isCheckingSession = false;
                        }
                    });
                } else {
                    doLogin().then(res => {
                        resolve(res);
                    }).catch(err => {
                        reject(err);
                    });
                }
            });
        }
        }
        }

静默续期的接口请求

至此,我们可以封装一个简单的接口,来在每次登录态过期的时候自动续期:

1.在请求前,使用checkSession()检车本次周期内session_key是否有效,无效则doLogin()拉起登录获取sessionId

2.请求接口,若返回特定登录态失效错误码(此处假设为LOGIN_FAIL_CODE),则doLogin()拉起登录获取sessionId

3.使用tryLoginCount来标志重试次数,TRY_LOGIN_LIMIT来标志重试次数上限,避免进入死循环。

代码语言:javascript
复制
import {doLogin} from "./doLogin";
        import {SESSION_KEY} from "./doLogin";
        import {checkSession} from "./checkSession";
        // 会话过期错误码,需要重新登录
        export const LOGIN_FAIL_CODES = [10000];
        const TRY_LOGIN_LIMIT = 3;
        export function request(obj: any = {}): Promise<object> {
            return new Promise((resolve, reject) => {
                checkSession().then(() => {
                    let session = wx.getStorageSync(SESSION_KEY);
                    const {url, data, method, header, dataType} = obj;
                    let tryLoginCount = obj.tryLoginCount || 0;
                    // 如果需要通过 data 把登录态 sessionId 带上const
                    dataWithSession = {...data, [SESSION_KEY]: session, appid: APPID};
                    wx.request({
                        url, data: dataWithSession, method, header, dataType, success: (res: any) => {
                            if (res.statusCode === 200) {
                                const data: ICommonResponse = res.data;
                                // 登陆态失效特定错误码判断,且重试次数未达到上限
                                if (LOGIN_FAIL_CODES.indexOf(data.return_code) > -1 && tryLoginCount < TRY_LOGIN_LIMIT) {
                                    doLogin().then(() => {
                                        obj.tryLoginCount = ++tryLoginCount;
                                        request(obj).then(res => {
                                            resolve(res);
                                        }).catch(err => {
                                            reject(err);
                                        });
                                    });
                                } else {
                                    resolve(res);
                                }
                            } else {
                                reject(res);
                            }
                        }, fail: function (err) {
                            reject(err);
                        }
                    });
                }).catch(err => {
                    reject(err);
                });
            });
        }

至此,我们大概包装了一个能自动登录或是进行静默续期的一个请求接口。

结束语


小程序的登录和登录态管理,大概是大部分小程序都需要的能力。codesession_key的设计,做了哪些事情来保护用户的数据。 如何在全局范围地保证登录态的有效性,微信侧的登录态也好,业务侧的登录态也好,静默续期的能力能给用户带来不少的体验提升。


内容来自网络,PHPer技术栈收集,如有侵权,请告知。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PHPer技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 小程序登录
    • 登录时序
      • 相关数据或参数
        • 加锁的登录
        • 登录态静默续期的实现
          • checkSession
            • 静默续期的接口请求
            • 结束语
            相关产品与服务
            访问管理
            访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档