Design and Implementation of Login and Authorization in WeChat Mini Programs
This article presents a comprehensive design for WeChat Mini Program login and authorization, detailing business scenarios, silent‑login flow with token management, fault‑tolerant session handling, step‑wise UI components for user and phone permissions, and a clear front‑end/back‑end API contract within a layered architecture.
This article discusses the design of a robust login/registration module for WeChat Mini Programs, covering business scenarios, core concepts, detailed implementation, and the interaction protocol between front‑end and back‑end.
1. Business Scenarios
Three typical scenarios are described:
Phone‑number based registration for e‑commerce platforms.
User‑profile acquisition (nickname, unionId) after login.
Combined scenarios requiring both phone number and profile.
2. Core Concepts
The article defines the difference between login (account + password) and registration (account creation). It also introduces the notion of “silent login” in Mini Programs, which is analogous to SSO in web applications.
3. Detailed Design
3.1 Silent Login Flow
The silent login consists of three steps:
Front‑end calls wx.login() to obtain a temporary code and sends it to the back‑end.
Back‑end exchanges the code for openId and session_key from WeChat.
Back‑end creates a custom token and returns it together with user info to the front‑end.
Key implementation points include:
Encapsulating wx.login() in a session.login() method to control side effects.
Handling the call timing (app launch vs. page load) with a status‑machine.
Managing concurrent login requests by blocking subsequent calls until the first finishes.
Detecting token expiration and providing a forced login option.
Example of a status‑machine integration (wrapped in code tags):
import { Status } from '@beautywe/plugin-status';</code>
<code>App({</code>
<code> status: { login: new Status('login') },</code>
<code> onLaunch() {</code>
<code> session.login()</code>
<code> .then(() => this.status.login.success())</code>
<code> .catch(() => this.status.login.fail());</code>
<code> } });3.2 Asynchronous Silent‑Login Handling
A session.ensureLogin() helper is used in request interceptors to guarantee a valid login state before sending a request that requires authentication.
fly.interceptors.request.use(async (req) => {</code>
<code> if (req.needLogin !== false) {</code>
<code> await session.ensureLogin();</code>
<code> const token = await session.getToken();</code>
<code> Object.assign(req.headers, { Authorization: token });</code>
<code> }</code>
<code> return req;</code>
<code>});3.3 Custom Token Expiration & Session‑Key Fault Tolerance
The article proposes a fuse‑line mechanism to limit the number of refresh attempts and a lock‑queue to serialize concurrent refreshes.
class Session {</code>
<code> refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;</code>
<code> refreshLoginFuseLocked = false;</code>
<code> async refreshLoginFuse() {</code>
<code> if (this.refreshLoginFuseLocked) return Promise.reject('fuse locked');</code>
<code> if (this.refreshLoginFuseLine > 0) {</code>
<code> this.refreshLoginFuseLine--;</code>
<code> return Promise.resolve();</code>
<code> }</code>
<code> this.refreshLoginFuseLocked = true;</code>
<code> setTimeout(() => {</code>
<code> this.refreshLoginFuseLocked = false;</code>
<code> this.refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;</code>
<code> }, this.refreshLoginFuseRestoreTime);
<code> return Promise.reject('fuse tripped');</code>
<code> }</code>
<code> // ... other methods ...</code>
<code>}Before using APIs that depend on session_key, the code checks its validity:
const ensureSessionKey = async () => {</code>
<code> const hasSession = await new Promise(resolve => {</code>
<code> wx.checkSession({ success: () => resolve(true), fail: () => resolve(false) });</code>
<code> });</code>
<code> if (!hasSession) {</code>
<code> logger.info('session_key expired, refreshing login');</code>
<code> return session.refreshLogin();</code>
<code> }</code>
<code> return Promise.resolve();</code>
<code>};4. Authorization Implementation
The authorization flow is split into three steps (represented by an AuthStep enum) and three UI components:
export enum AuthStep { ONE = 1, TWO = 2, THREE = 3 } <user-container>: wraps the user‑info button. <phone-container>: wraps the phone‑number button. <auth-flow>: composes the above components according to the required step.
The component decides which UI to show based on the current step and the target step ( mustAuthStep).
<view class="auth-flow"></code>
<code> <block wx:if="{{currAuthStep === mustAuthStep || currAuthStep === AuthStep.THREE}}"></code>
<code> 已完成授权</code>
<code> </block></code>
<code> <block wx:elif="{{currAuthStep === AuthStep.ONE}}"></code>
<code> <user-container bind:getuserinfo="nextStep"></code>
<code> <view>授权用户信息</view></code>
<code> </user-container></code>
<code> </block></code>
<code> <block wx:elif="{{currAuthStep === AuthStep.TWO}}"></code>
<code> <phone-container bind:getphonenumber="nextStep"></code>
<code> <view>授权手机号</view></code>
<code> </phone-container></code>
<code> </block></code>
<code></view>A mustAuth helper (or decorator) can be used in page logic to guarantee that the required authorization step is satisfied before executing business code.
class Session {</code>
<code> mustAuth({ mustAuthStep = AuthStep.TWO, popupCompName = 'auth-popup', mode = AuthDisplayMode.POPUP } = {}) {</code>
<code> if (this.currentAuthStep() >= mustAuthStep) return Promise.resolve();</code>
<code> const pages = getCurrentPages();</code>
<code> const curPage = pages[pages.length - 1];</code>
<code> const popupComp = curPage.selectComponent(`#${popupCompName}`);</code>
<code> if (!popupComp || mode === AuthDisplayMode.PAGE) {</code>
<code> const curRoute = curPage.route;</code>
<code> wx.redirectTo({ url: `authPage?backTo=${encodeURIComponent(curRoute)}` });</code>
<code> return Promise.resolve();</code>
<code> }</code>
<code> popupComp.setMustAuthStep(mustAuthStep);</code>
<code> popupComp.nextStep();</code>
<code> return new Promise((resolve, reject) => {</code>
<code> const authStatus = getApp().status.auth;</code>
<code> authStatus.onceSuccess(resolve);</code>
<code> authStatus.onceFail(reject);</code>
<code> });</code>
<code> }</code>
<code>}5. Back‑End Interaction Protocol
The article lists the minimal set of APIs required by the front‑end:
silentLogin : input code, output token and userInfo.
updateUser : update nickname and encrypted user data.
updatePhone : decrypt and store the phone number.
unbindPhone , logout : optional clean‑up endpoints.
6. Architecture Overview
The solution is divided into three layers:
Business customization layer (specific <auth‑flow> configurations).
Login service layer (session management, token refresh, status machine).
Underlying infrastructure (WeChat SDK, network library such as fly.js).
Diagram images are referenced in the original article (omitted here).
7. Conclusion
The article summarizes the key points:
Silent login and its asynchronous handling.
Fault‑tolerant token and session_key refresh mechanisms.
Component‑based UI for step‑wise authorization.
Clear front‑end/back‑end contract for login‑related APIs.
By following this design, developers can build a reusable, robust login & authorization solution for WeChat Mini Programs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent Cloud Developer
Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
