Understand the front-end design and implementation of WeChat mini program login

coldplay.xixi
Release: 2020-10-28 17:24:42
forward
3625 people have browsed it

TodayWeChat Mini Program Development column introduces the front-end design and implementation of mini program login.

1. Preface

The purpose of the login/registration design is of course to make this the basic capability of the application and be robust enough to avoid the occurrence of the whole site. sexual obstruction.

At the same time, we must fully consider how to decouple and encapsulate. When developing new small programs, we can quickly remove reuse capabilities and avoid repeated pitfalls.

The login and registration module is like an iceberg. We think it is just "enter your account and password, and you are logged in." But in fact, there are various issues that need to be considered.

Here, I would like to share with you all the design experiences and ideas I have accumulated after recently completing a small program login/registration module.

2. Business Scenario

In the process of users browsing the mini program, due to business needs, it is often necessary to obtain some basic information of the user. Common ones include:

  1. 微信nickname
  2. 微信手机

Different products have different information requirements for users, and will also have different authorization processes.

The first type is common in e-commerce systems. When users purchase goods, in order to identify the user's multi-platform account, they often use their mobile phone number to make a contact. In this case, the user needs to authorize the mobile phone number.

Understand the front-end design and implementation of WeChat mini program login

Second, in order to get basic initialization of user information, it is often necessary to obtain further user information: such as WeChat nickname, unionId, etc. User authorization is required.

Understand the front-end design and implementation of WeChat mini program login

The third type includes the first type and the second type.

Understand the front-end design and implementation of WeChat mini program login

3. Concept

With the goal of precipitating a set of universal mini program login solutions and services, let’s analyze the business and derive the variables.

Before doing technical design, talk some necessary nonsense and conduct basic tuning on some concepts.

2.1 About "Login"

Login is "login" in English, and the corresponding one is "logout". Before logging in, you need to have an account and "register" (or sign up).

It is said that the initial product did not have a login/registration function, but it gradually became available as more people used it. Due to the needs of the product itself, the "user" needs to be identified.

In the real society, each of us has an identity ID: ID card. When I turned 16, I completed a "registration" when I went to the Public Security Bureau to get my ID card for the first time. Then I went to the Internet cafe to surf the Internet, swiped my ID card, and completed the "login" behavior.

So for the Internet in the virtual world, this identity certificate is "account password".

Common login/registration methods are:

  1. Account and password registration

    In the early days of the Internet, personal email and mobile phone Coverage is small. Therefore, the user needs to think of an account name. We register a QQ account, which is this form.

    from 汽车之家

  2. Email address registration

    After the millennium, the PC Internet era has rapidly become popular, and we have all created Get your own personal email. In addition, QQ also comes with an email account. Since email is personal and private and can communicate information, most websites have begun to use email accounts as user names for registration, and during the registration process they will be asked to log in to the corresponding email to check for activation emails to verify that we have Ownership of the registered email address.

    from 支付宝

  3. Mobile Number Registration

    After the popularization of the Internet, smartphones and mobile Internet developed rapidly. Mobile phones have become an indispensable mobile device for everyone, and the mobile Internet has been deeply integrated into everyone's modern life. Therefore, compared to email, mobile phone numbers are currently more closely related to individuals, and more and more mobile applications are emerging, and registration methods that use mobile phone numbers as user names are also widely used.

    from 知乎

# By 2020, the number of WeChat users will reach 1.2 billion. Well, WeChat accounts, at least in China, have become the "identity mark" of the new generation of the Internet world.

For WeChat applet, it is natural to know the WeChat account ID of the current user. WeChat allows mini program applications to quietly "log in" to our mini program applications without the user being aware of it. This is what we often call "silent login."

In fact, the login of WeChat applet is essentially the same concept as the "single sign-on" of traditional web applications.

  1. Single sign-on: After logging in at station A, station C and station B can achieve fast "silent login".
  2. WeChat mini program login: In WeChat, if you log in to your WeChat account, you can achieve "silent login" in the entire mini program ecosystem.

Since Http is originally stateless, the industry’s basic general approach to login state is:

  1. cookie-session: commonly used in browser applications
  2. access token: often used in non-browser applications such as mobile terminals

In the WeChat applet, the "JS logic layer" is not a browser environment, and naturally there is no Cookie, then access token is usually used.

2.2 About "Authorization"

For products that need to further obtain user nicknames, user mobile phone numbers and other information. For the sake of user privacy, WeChat requires users to actively agree to authorize. Only mini program applications can obtain this part of the information. This is the interaction of the currently popular mini programs "authorized user information" and "authorized mobile phone number".

Due to the different sensitivities of different user information, WeChat mini programs provide different "authorization" methods for different user information:

  1. Call the specific API method, Pop-up authorization.
    1. For example, when calling wx.getLocation(), if the user is not authorized, the address authorization interface will pop up.
    2. If rejected, the window will not pop up again, and wx.getLocation() will directly return failure.
  2. <button open-type="xxx"></button> method.
    1. Only supports: user sensitive information and user mobile phone number. You need to cooperate with the backend for symmetric encryption and decryption to obtain the data.
    2. The user has declined. If you click the button again, the pop-up window will still appear.
  3. Through wx.authorize(), ask for authorization in advance, and there is no need to pop up the authorization again when you need to obtain relevant information later.

4. Detailed Design

After sorting out the concepts, our modules can be divided into two large blocks:

  1. Login: Responsible for creating a session with the server. This session implements silent login and related fault-tolerance processing. The module is named: Session
  2. ##Authorization: Responsible for interacting with users, obtaining and updating information, and controlling permissions, etc. The module is named: Auth
  3. ##3.1 Login implementation

3.1 .1 Silent login

Understand the front-end design and implementation of WeChat mini program loginThe official login solution provided by WeChat is summarized in three steps:

The front end passes
    wx.login()
  1. Obtain the one-time encryption certificate code and hand it to the backend. The backend transmits this code to the WeChat server in exchange for the user's unique identifier
  2. openId
  3. and authorization certificate session_key. (Special API calls used for subsequent server-side and WeChat servers, see for details: WeChat official documentation - server-side acquisition of open data). The backend transmits the user credentials obtained from the WeChat server and the self-generated login credentials (token) to the frontend. The front end saves it and brings it to the back end the next time it is requested, so that it can identify which user.
  4. If you just implement this process, it is quite simple.

But to achieve a robust login process, you need to pay attention to more edge cases:

  1. Collapse

    wx.login() Call : Because

    wx.login()

    will produce unpredictable side effects, for example, it may cause session_key to become invalid, resulting in subsequent authorization Failure in decryption scenarios. We can provide a method like session.login() here to take control of wx.login() and perform a series of encapsulation and fault tolerance processing on it.

  2. Timing of the call

    : Usually when the application starts (

    app.onLaunch()

    ), Go to initiate a silent login. However, there is an asynchronous problem caused by the applet life cycle design problem: when loading the page, when calling a back-end API that requires login state, the previous asynchronous static login process may not be completed, resulting in a request fail. <p> Of course, you can also initiate a login call in an asynchronous blocking manner when the first interface that requires login status is called. This requires a well-designed interface layer. </p> <p>The detailed design ideas for the two scenarios mentioned above will be discussed below. </p>

  3. Problems with concurrent calls:

    In business scenarios, it is inevitable that there will be multiple codes that need to trigger login. If you encounter extreme situations, These multiple codes initiate calls at the same time. That will cause the login process to be initiated multiple times in a short period of time, even though the previous request has not been completed. For this situation, we can block the first call and wait for the result of subsequent calls, just like the process of combining sperm and eggs.

  4. Problems with unexpired calls:

    If our login status has not expired, it can be used normally. By default, there is no need to call again. Go and initiate the login process. At this time, we can first check whether the login state is available by default. If not, we can initiate a request. Then you can also provide a parameter similar to session.login({ force: true }) to force login.

3.1.2 Handling of silent login asynchronous state

1. Called when the application starts

because in most cases They all need to rely on the login state. We will naturally think of calling this call when the application starts (app.onLaunch()).

However, due to the native applet startup process, the life cycle hook functions of App, Page, Component do not support asynchronous blocking. .

Then we can easily encounter that the "login process" initiated by app.onLaunch has not been completed at page.onLoad, and we will not be able to do it correctly. Some operations rely on login status.

In response to this situation, we designed a state machine tool: status

Understand the front-end design and implementation of WeChat mini program login

Based on the state machine, we can write code like this:

import { Status } from '@beautywe/plugin-status';// on app.jsApp({    status: {       login: new Status('login');
    },    onLaunch() {
        session            // 发起静默登录调用
            .login()            // 把Understand the front-end design and implementation of WeChat mini program login设置为 success
            .then(() => this.status.login.success())      
            // 把Understand the front-end design and implementation of WeChat mini program login设置为 fail
            .catch(() => this.status.login.fail());
    },
});// on page.jsPage({    onLoad() {      const loginStatus = getApp().status.login;      
      // must 里面会进行状态的判断,例如登录中就等待,登录成功就直接返回,登录失败抛出等。
      loginStatus().status.login.must(() => {        // 进行一些需要登录态的操作...
      });
    },
});复制代码
Copy after login

2. Initiate login when the "first interface that requires login state" is called

Further, we will find that a deeper level of login state is required The node is when launching the "backend API that requires login status".

Then we can initiate "silent login" when calling "backend API that requires login status". For concurrent scenarios, just let other requests wait.

Using fly.js as the "network request layer" encapsulated by wx.request(), make a simple example:

// 发起请求,并表明该请求是需要登录态的fly.post('https://...', params, { needLogin: true });// 在 fly 拦截器中处理逻辑fly.interceptors.request.use(async (req)=>{  // 在请求需要登录态的时候
  if (req.needLogin !== false) {    // ensureLogin 核心逻辑是:判断是否已登录,如否发起登录调用,如果正在登录,则进入队列等待回调。
    await session.ensureLogin();    
    // 登录成功后,获取 token,通过 headers 传递给后端。
    const token = await session.getToken();    Object.assign(req.headers, { [AUTH_KEY_NAME]: token });
  }  
  return req;
});复制代码
Copy after login

3.1.3 Custom login state Expired fault-tolerance processing

When the custom login state expires, the backend needs to return a specific status code, such as: AUTH_EXPIRED, AUTH_INVALID, etc.

The front end can monitor the status code of all requests in the "network request layer", and then initiate a refresh of the login status, and then replay the failed request:

// 添加响应拦截器fly.interceptors.response.use(    (response) => {      const code = res.data;        
      // 登录态过期或失效
      if ( ['AUTH_EXPIRED', 'AUTH_INVALID'].includes(code) ) {      
        // 刷新登录态
        await session.refreshLogin();        
        // 然后重新发起请求
        return fly.request(request);
      }
    }
)复制代码
Copy after login

Then if there are multiple concurrent requests Each request returns a status code indicating that the login status is invalid, and the above code will be executed multiple times.

We need to do some special fault-tolerance processing for session.refreshLogin():

  1. Request lock: At the same time, only A network request in progress.
  2. Waiting queue: After the request is locked, all calls to this method are pushed into a queue, waiting for the network request to be completed to share the return result.
  3. Circuit breaker mechanism: If called multiple times in a short period of time, it will stop responding for a period of time, similar to TCP slow start.

Sample code:

class Session {  // ....
  
  // 刷新登录保险丝,最多重复 3 次,然后熔断,5s 后恢复
  refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;
  refreshLoginFuseLocked = false;
  refreshLoginFuseRestoreTime = 5000;  // 熔断控制
  refreshLoginFuse(): Promise<void> {    if (this.refreshLoginFuseLocked) {      return Promise.reject('刷新登录-保险丝已熔断,请稍后');
    }    if (this.refreshLoginFuseLine > 0) {      this.refreshLoginFuseLine = this.refreshLoginFuseLine - 1;      return Promise.resolve();
    } else {      this.refreshLoginFuseLocked = true;      setTimeout(() => {        this.refreshLoginFuseLocked = false;        this.refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;
        logger.info('刷新登录-保险丝熔断解除');
      }, this.refreshLoginFuseRestoreTime);      return Promise.reject('刷新登录-保险丝熔断!!');
    }
  }  // 并发回调队列
  refreshLoginQueueMaxLength = 100;
  refreshLoginQueue: any[] = [];
  refreshLoginLocked = false;  // 刷新登录态
  refreshLogin(): Promise<void> {    return Promise.resolve()    
      // 回调队列 + 熔断 控制
      .then(() => this.refreshLoginFuse())
      .then(() => {        if (this.refreshLoginLocked) {          const maxLength = this.refreshLoginQueueMaxLength;          if (this.refreshLoginQueue.length >= maxLength) {            return Promise.reject(`refreshLoginQueue 超出容量:${maxLength}`);
          }          return new Promise((resolve, reject) => {            this.refreshLoginQueue.push([resolve, reject]);
          });
        }        this.refreshLoginLocked = true;
      })      // 通过前置控制之后,发起登录过程
      .then(() => {        this.clearSession();
        wx.showLoading({ title: '刷新登录态中', mask: true });        return this.login()
          .then(() => {
            wx.hideLoading();
            wx.showToast({ icon: 'none', title: '登录成功' });            this.refreshLoginQueue.forEach(([resolve]) => resolve());            this.refreshLoginLocked = false;
          })
          .catch(err => {
            wx.hideLoading();
            wx.showToast({ icon: 'none', title: '登录失败' });            this.refreshLoginQueue.forEach(([, reject]) => reject());            this.refreshLoginLocked = false;            throw err;
          });
      });  // ...}复制代码</void></void>
Copy after login

3.1.4 Fault tolerance processing of WeChat session_key expiration

After we start the "silent login" above, the WeChat server will issue A session_key is given to the backend, and this will be used when it is necessary to obtain WeChat open data.

Understand the front-end design and implementation of WeChat mini program login

And session_key is time-sensitive. The following is taken from the official description of WeChat:

Session key session_key validity

If developers encounter signature verification failure or decryption failure due to incorrect session_key, please pay attention to the following precautions related to session_key.

  1. wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 auth.code2Session 接口更新服务器存储的 session_key。
  2. 微信不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
  3. 开发者在 session_key 失效时,可以通过重新执行登录流程获取有效的 session_key。使用接口 wx.checkSession可以校验 session_key 是否有效,从而避免小程序反复执行登录流程。
  4. 当开发者在实现自定义登录态时,可以考虑以 session_key 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。

翻译成简单的两句话:

  1. session_key 时效性由微信控制,开发者不可预测。
  2. wx.login 可能会导致 session_key 过期,可以在使用接口之前用 wx.checkSession 检查一下。

而对于第二点,我们通过实验发现,偶发性的在 session_key 已过期的情况下,wx.checkSession 会概率性返回 true

社区也有相关的反馈未得到解决:

  • 小程序解密手机号,隔一小段时间后,checksession:ok,但是解密失败
  • wx.checkSession有效,但是解密数据失败
  • checkSession判断session_key未失效,但是解密手机号失败

所以结论是:wx.checkSession可靠性是不达 100% 的。

基于以上,我们需要对 session_key 的过期做一些容错处理:

  1. 发起需要使用 session_key 的请求前,做一次 wx.checkSession 操作,如果失败了刷新登录态。
  2. 后端使用 session_key 解密开放数据失败之后,返回特定错误码(如:DECRYPT_WX_OPEN_DATA_FAIL),前端刷新登录态。

示例代码:

// 定义检查 session_key 有效性的操作const ensureSessionKey = async () => {  const hasSession = await new Promise(resolve => {
    wx.checkSession({      success: () => resolve(true),      fail: () => resolve(false),
    });
  });  
  if (!hasSession) {
    logger.info('sessionKey 已过期,刷新登录态');    // 接上面提到的刷新登录逻辑
    return session.refreshLogin();
  }  return Promise.resolve();
}// 在发起请求的时候,先做一次确保 session_key 最新的操作(以 fly.js 作为网络请求层为例)const updatePhone = async (params) => {  await ensureSessionKey();  const res = await fly.post('https://xxx', params);
}// 添加响应拦截器, 监听网络请求返回fly.interceptors.response.use(    (response) => {      const code = res.data;        
      // 登录态过期或失效
      if ( ['DECRYPT_WX_OPEN_DATA_FAIL'].includes(code)) {        // 刷新登录态
        await session.refreshLogin();        
        // 由于加密场景的加密数据由用户点击产生,session_key 可能已经更改,需要用户重新点击一遍。
        wx.showToast({ title: '网络出小差了,请稍后重试', icon: 'none' });
      }
    }
)复制代码
Copy after login

3.2 授权的实现

3.2.1 组件拆分与设计

在用户信息和手机号获取的方式上,微信是以 <button open-type="'xxx'"></button> 的方式,让用户主动点击授权的。

那么为了让代码更解耦,我们设计这样三个组件:

  1. <user-contaienr getuserinfo="onUserInfoAuth"></user-contaienr>: 包装点击交互,通过 <slot></slot> 支持点击区域的自定义UI。
  2. <phone-container getphonennmber="onPhoneAuth"></phone-container> : 与 <user-container></user-container> 同理。
  3. <auth-flow></auth-flow>: 根据业务需要,组合 <user-container></user-container><phone-container></phone-container> 组合来定义不同的授权流程。

以开头的业务场景的流程为例,它有这样的要求:

  1. 有多个步骤。
  2. 如果中途断掉了,可以从中间接上。
  3. 有些场景中,只要求达到「用户信息授权」,而不需要完成「用户手机号」。

Understand the front-end design and implementation of WeChat mini program login

那么授权的阶段可以分三层:

// 用户登录的阶段export enum AuthStep {  // 阶段一:只有登录态,没有用户信息,没有手机号
  ONE = 1,  // 阶段二:有用户信息,没有手机号
  TWO = 2,  // 阶段三:有用户信息,有手机号
  THREE = 3,
}复制代码
Copy after login

AuthStep 的推进过程是不可逆的,我们可以定义一个 nextStep 函数来封装 AuthStep 更新的逻辑。外部使用的话,只要无脑调用 nextStep 方法,等待回调结果就行。

示例伪代码:

// auth-flow componentComponent({  // ...
  
  data: {    // 默认情况下,只需要到达阶段二。
    mustAuthStep: AuthStep.TWO
  },  
  // 允许临时更改组件的需要达到的阶段。
  setMustAuthStep(mustAuthStep: AuthStep) {    this.setData({ mustAuthStep });
  },  
  // 根据用户当前的信息,计算用户处在授权的阶段
  getAuthStep() {    let currAuthStep;    
    // 没有用户信息,尚在第一步
    if (!session.hasUser() || !session.hasUnionId()) {
      currAuthStep = AuthStepType.ONE;
    }    // 没有手机号,尚在第二步
    if (!session.hasPhone()) {
      currAuthStep = AuthStepType.TWO;
    }    // 都有,尚在第三步
    currAuthStep = AuthStepType.THREE;    return currAuthStep;
  }  
  // 发起下一步授权,如果都已经完成,就直接返回成功。
  nextStep(e) {    const { mustAuthStep } = this.data;    const currAuthStep = this.updateAuthStep();  
    // 已完成授权
    if (currAuthStep >= mustAuthStep || currAuthStep === AuthStepType.THREE) {      // 更新全局的授权Understand the front-end design and implementation of WeChat mini program login,广播消息给订阅者。
      return getApp().status.auth.success();
    }    // 第一步:更新用户信息
    if (currAuthStep === AuthStepType.ONE) {      // 已有密文信息,更新用户信息
      if (e) session.updateUser(e);      // 更新到视图层,展示对应UI,等待获取用户信息
      else this.setData({ currAuthStep });      return;
    }    // 第二步:更新手机信息
    if (currAuthStep === AuthStepType.TWO) {      // 已有密文信息,更新手机号
      if (e) this.bindPhone(e);      // 未有密文信息,弹出获取窗口
      else this.setData({ currAuthStep });      return;
    }    console.warn('auth.nextStep 错误', { currAuthStep, mustAuthStep });
  },  
  // ...});复制代码
Copy after login

那么我们的 <auth-flow></auth-flow> 中就可以根据 currAuthStepmustAuthStep 来去做不同的 UI 展示。需要注意的是使用 <user-container></user-container><phone-container></phone-container> 的时候连接上 nextStep(e) 函数。

示例伪代码:

<view>

  <!-- 已完成授权 -->
  <block>
    <view>已完成授权</view>
  </block>

  <!-- 未完成授权,第一步:Understand the front-end design and implementation of WeChat mini program login -->
  <block>
    <user-container>
      <view>Understand the front-end design and implementation of WeChat mini program login</view>
    </user-container>
  </block>

  <!-- 未完成授权,第二步:Understand the front-end design and implementation of WeChat mini program login -->
  <block>
    <phone-container>
      <view>Understand the front-end design and implementation of WeChat mini program login</view>
    </phone-container>
  </block>
  </view>复制代码
Copy after login

3.2.2 权限拦截的处理

到这里,我们制作好了用来承载授权流程的组件 <auth-flow></auth-flow> ,那么接下来就是决定要使用它的时机了。

我们梳理需要授权的场景:

  1. 点击某个按钮,例如:购买某个商品。

    对于这种场景,常见的是通过弹窗完成授权,用户可以选择关闭。

    Understand the front-end design and implementation of WeChat mini program login

  2. 浏览某个页面,例如:访问个人中心。

    对于这种场景,我们可以在点击跳转某个页面的时候,进行拦截,弹窗处理。但这样的缺点是,跳转到目标页面的地方可能会很多,每个都拦截,难免会错漏。而且当目标页面作为「小程序落地页面」的时候,就避免不了。

    这时候,我们可以通过重定向到授权页面来完成授权流程,完成之后,再回来。

    Understand the front-end design and implementation of WeChat mini program login

那么我们定义一个枚举变量:

// 授权的展示形式export enum AuthDisplayMode {  // 以弹窗形式
  POPUP = 'button',  // 以页面形式
  PAGE = 'page',
}复制代码
Copy after login

我们可以设计一个 mustAuth 方法,在点击某个按钮,或者页面加载的时候,进行授权控制。

伪代码示例:

class Session {  // ...
  
  mustAuth({
    mustAuthStep = AuthStepType.TWO, // 需要授权的LEVEL,默认需要获取用户资料
    popupCompName = 'auth-popup',	// 授权弹窗组件的 id
    mode = AuthDisplayMode.POPUP, // 默认以弹窗模式
  } = {}): Promise<void> {    
    // 如果当前的授权步骤已经达标,则返回成功
    if (this.currentAuthStep() >= mustAuthStep) return Promise.resolve();    // 尝试获取当前页面的 <auth-popup></auth-popup> 组件实例
    const pages = getCurrentPages();    const curPage = pages[pages.length - 1];    const popupComp = curPage.selectComponent(`#${popupCompName}`);    // 组件不存在或者显示指定页面,跳转到授权页面
    if (!popupComp || mode === AuthDisplayMode.PAGE) {      const curRoute = curPage.route;      // 跳转到授权页面,带上当前页面路由,授权完成之后,回到当前页面。
      wx.redirectTo({ url: `authPage?backTo=${encodeURIComponent(curRoute)}` });      return Promise.resolve();
    }    
    // 设置授权 LEVEL,然后调用 <auth-popup> 的 nextStep 方法,进行进一步的授权。
    popupComp.setMustAuthStep(mustAuthStep);
    popupComp.nextStep();    // 等待成功回调或者失败回调
    return new Promise((resolve, reject) => {      const authStatus = getApp().status.auth;
      authStatus.onceSuccess(resolve);
      authStatus.onceFail(reject);
    });
  }  
  // ...}复制代码</auth-popup></void>
Copy after login

那么我们就能在按钮点击,或者页面加载的时候进行授权拦截:

Page({  onLoad() {
    session.mustAuth().then(() => {      // 开始初始化页面...
    });
  }  
  onClick(e) {
    session.mustAuth().then(() => {      // 开始处理回调逻辑...
    });
  }
})复制代码
Copy after login

当然,如果项目使用了 TS 的话,或者支持 ES7 Decorator 特性的话,我们可以为 mustAuth 提供一个装饰器版本:

export function mustAuth(option = {}) {  return function(
    _target,
    _propertyName,
    descriptor,  ) {    // 劫持目标方法
    const method = descriptor.value;    
    // 重写目标方法
    descriptor.value = function(...args: any[]) {      return session.mustAuth(option).then(() => {        // 登录完成之后,重放原来方法
        if (method) return method.apply(this, args);
      });
    };
  };
}复制代码
Copy after login

那么使用方式就简单一些了:

Page({
  @mustAuth();  onLoad() {    // 开始初始化页面...
  }
  
  @mustAuth();  onClick(e) {    // 开始处理回调逻辑...
  }
});复制代码
Copy after login

3.3. 前后端交互协议整理

作为一套可复用的小程序登录方案,当然需要去定义好前后端的交互协议。

那么整套登录流程下来,需要的接口有这么几个:

Understand the front-end design and implementation of WeChat mini program login

  1. 静默登录 silentLogin

    1. 入参:
      1. code: 产自 wx.login()
    2. 出参:
      1. token: 自定义登录态凭证
      2. userInfo: 用户信息
    3. 说明:
      1. 后端利用 code 跟微信客户端换取用户标识,然后注册并登录用户,返回自定义登录态 token 给前端
      2. token 前端会存起来,每个请求都会带上
      3. userInfo 需要包含nicknamephone字段,前端用于计算当前用户的授权阶段。当然这个状态的记录可以放在后端,但是我们认为放在前端,会更加灵活。
  2. 更新用户信息 updateUser

    1. 入参:
      1. nickname: 用户昵称
      2. encrypt: Understand the front-end design and implementation of WeChat mini program login相关的 iv, encryptedData
      3. 以及其他如性别地址等非必要字段
    2. 出参:
      1. userInfo:更新后的最新用户信息
    3. 说明:
      1. 后端解密Understand the front-end design and implementation of WeChat mini program login,获取隐蔽数据,如:unionId
      2. 后端支持更新包括 nickname等用户基本信息。
      3. 前端会把 userInfo 信息更新到 session 中,用于计算授权阶段。
  3. 更新用户手机号 updatePhone

    1. 入参:
      1. encrypt:Understand the front-end design and implementation of WeChat mini program login相关的 iv, encryptedData
    2. 出参:
      1. userInfo:更新后的最新用户信息
    3. 说明:
      1. 后端解密开放式局,获取手机号,并更新到用户信息中。
      2. 前端会把 userInfo 信息更新到 session 中,用于计算授权阶段。
  4. 解绑手机号 unbindPhone

    1. 入参:-
    2. 出参:-
    3. 说明:后端解绑用户手机号,成功与否,走业务定义的前后端协议。
  5. 登录 logout

    1. 入参:-

    2. 出参:-

    3. 说明:后端主动过期登录态,成功与否,走业务定义的前后端协议。

五. 架构图

最后我们来梳理一下整体的「登录服务」的架构图:

Understand the front-end design and implementation of WeChat mini program login

由「登录服务」和「底层建设」组合提供的通用服务,业务层只需要去根据产品需求,定制授权的流程 <auth-flow></auth-flow> ,就能满足大部分场景了。

六. 总结

本篇文章通过一些常见的登录授权场景来展开来描述细节点。

整理了「登录」、「授权」的概念。

然后分别针对「登录」介绍了一些关键的技术实现:

  1. Silent login
  2. Handling of silent login asynchronous state
  3. Fault-tolerant processing of custom login state expiration
  4. WeChatsession_key Expired Fault-tolerant processing

As for "authorization", there will be the logic of designing the UI part, and it also needs to involve the splitting of components:

  1. Component splitting and design
  2. Processing of permission interception

Then, we sorted out the back-end interfaces that this login authorization scheme relies on, and gave the simplest reference protocol.

Finally, from the perspective of "with the goal of precipitating a set of universal mini program login solutions and services", we sorted out the layering at the architectural level.

  1. Business customization layer
  2. Login service layer
  3. Underlying construction

Related free learning recommendations:WeChat Mini Program Development

The above is the detailed content of Understand the front-end design and implementation of WeChat mini program login. For more information, please follow other related articles on the PHP Chinese website!

source:juejin.im
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template