Welcome to my blog: “Front-end Design and Implementation of micro channel Small Program Login”
A preface.
The purpose of the login/registration design is, of course, to make it robust enough to avoid site-wide blocking as an underlying capability of the application.
At the same time, how to fully consider decoupling and encapsulation, in the development of a new small program, can be faster to reuse capacity, to avoid repeated pit.
Registering for this module is like an iceberg. We think of it as “enter your password and you’re logged in”, but there are all sorts of things to consider below.
Here, to share with you, recently finished a small program login/registration module, precipitation down some design experience and ideas.
2. Service scenarios
In the process of users browsing small programs, businesses often need to obtain some basic information of users, the common ones are:
- WeChat nickname
- Wechat mobile number
Different products have different requirements on user information and have different authorization procedures.
The first one is common in e-commerce systems. When users purchase goods, in order to identify users’ multi-platform accounts, they often use their mobile phone number to make a contact. At this time, users need to authorize their mobile phone number.
Second, in order to get the basic initialization of user information, it is often necessary to further obtain user information: such as wechat nickname, unionId, etc., user authorization needs to be asked.
The third way, the first way, the second way.
Concept of three.
With the goal of developing a common applet login solution and service, we analyze the business and derive the variables.
Before we do the technical design, a bit of necessary nonsense, basic FM for some concepts.
2.1 About Login
Login is also logged out. To log in, you need to register (or sign up) with an account.
At the beginning of the product is no login/registration function, use more people slowly have. For the sake of the product itself, “users” need to be identified.
In the real society, each of us has an identity ID: ID card. When I was 16 years old, I went to the public security bureau to get my ID card for the first time, and I completed a “registration”. Then I went to Internet cafes to get online, id card brush once, completed a “login” behavior.
For the Internet of the virtual world, this proof of identity is “account number + password”.
Common login/registration methods are:
-
Account and Password Registration
In the early days of the Internet, personal email and mobile phone coverage was small. Therefore, users need to think of an account name, we register a QQ number, is this form.
-
Email Address Registration
After the turn of the millennium, with the rapid spread of the PC Internet, we all created our own personal email accounts. Plus QQ also bring mailbox account. Due to the privacy of email and the ability to communicate information, most websites start to use email accounts as user names to register, and in the process of registration, they will be required to log in to the corresponding email to check the activation mail and verify our ownership of the registered email.
-
Registration of mobile phone number
After the popularization of the Internet, smart phones and mobile Internet have developed rapidly. Mobile phones have become indispensable mobile devices for everyone, and mobile Internet has been deeply integrated into everyone’s modern life. Therefore, compared with email, mobile phone number is more closely related to individuals at present, and more and more mobile applications appear, and the registration method of using mobile phone number as user name is also widely used.
By 2020, wechat will have 1.2 billion users. So wechat accounts, at least in China, have become the “identity mark” of the new Internet world.
And for wechat small program, naturally can know the current user’s wechat account ID. Wechat allows small program applications to “log in” to our small program without the user being aware of it. This is often called “silent login”.
In fact, the login of wechat applets is essentially the same concept as the “single sign-on” of traditional Web applications.
- Single sign-on (SSO) : If you log in at site A, sites C and B can achieve rapid “silent login”.
- Wechat mini program login: in wechat, login wechat account, then in the whole mini program ecosystem, can achieve “silent login”.
Since Http is stateless, the general approach to login state is as follows:
- Cookie-session: used in browser applications
- Access Token: Used for non-browser applications such as mobile terminal
In wechat small program, for the “JS logic layer” is not a browser environment, naturally there is no Cookie, then usually use access token.
2.2 About Authorization
For the need to further obtain the user nickname, user phone number and other information of the product. For the sake of users’ privacy, wechat requires users to actively agree to authorize it. Small program application can obtain this part of the information, which has the current popular small program “authorized user information”, “authorized mobile phone number” interaction.
Due to different sensitivities of user information, wechat applets provide “authorization” for different user information in different ways:
- Call specific API way, popover authorization.
- For example, when wx.getLocation() is called, if the user is not authorized, the address authorization screen is displayed.
- If you say no, it won’t pop over again,
wx.getLocation()
Return failure directly.
<button open-type="xxx" />
Way.- Only sensitive user information and user mobile phone number can be obtained by symmetric encryption and decryption with the backend.
- The user has refused to click the button again and it will still pop up.
- Through wx.authorize(), the authorization is queried in advance so that the authorization does not pop up again when relevant information needs to be obtained later.
4. Detailed design
After sorting out the concept, we can divide the module into two chunks:
- The login: is responsible for creating a session with the server, which implements silent login and related fault tolerance, etc., named as:
Session
- authorization: Responsible for interacting with users, obtaining and updating information, and controlling and processing permissions, etc. The module is named as:
Auth
3.1 Implementation of login
3.1.1 Silent Login
The login scheme provided by wechat official can be summarized into three steps:
- Front end by
wx.login()
Get one-time encryption certificate code and hand it to the back end. - The backend transmits this code to the wechat server in exchange for the unique identity of the user
openId
And authorization certificatesession_key
. (Special API calls for subsequent server-side and wechat server, see:Wechat official document – server access to open data). - The backend transmits the user credentials obtained from the wechat server and the login status credentials (tokens) generated by itself to the front-end. The front end saves it and brings it to the back end on the next request so it can identify which user.
If you just implement the process, it’s pretty easy.
But to implement a robust login process, there are more boundary cases to be aware of:
-
Wrap up the wx.login() call:
Wx.login () has unpredictable side effects, such as session_key failure, which can lead to failure in subsequent authorized decryption scenarios. We can provide a method like session.login(), take control of wx.login(), and do a bunch of encapsulation and fault tolerance on it.
-
Call timing:
Normally we would initiate a silent login at app launch (app.onlaunch ()). However, there is an asynchronous problem caused by applets lifecycle design issues: when a page is loaded, the asynchronous static login process may not have been completed before calling a back-end API that requires a logon state, causing the request to fail.
Of course, it is also possible to initiate a login call asynchronously blocking the first time the login interface is called, and this requires a well-designed interface layer.
Detailed design ideas for the two scenarios mentioned above will be described below.
-
Problems with concurrent calls:
In business scenarios, it is inevitable that there will be multiple codes that need to trigger the login, and in extreme cases, these codes will be invoked at the same time. This can result in a short number of times initiating the login process, even though the previous request has not been completed. In this case, we can block the first call and wait for the result of subsequent calls, just like sperm and egg.
-
Problems with unexpired calls:
If our login state is not expired, it can be used normally. By default, there is no need to initiate the login process. By default, we can check whether the login state is available, and then initiate a request. You can then provide an argument like session.login({force: true}) to forcibly initiate a login.
3.1.2 Processing asynchronous Status of Silent Login
1. Called when the application starts
Since most situations depend on the login state, it would be natural to make this call when the app is launched (app.onlaunch ()).
But asynchronous blocking is not supported by the App, Page, and Component lifecycle hook functions in the native applet startup process.
Therefore, it is easy for us to encounter that the “login process” initiated by app.onLaunch has not been completed at the time of Page. onLoad, so we cannot properly perform some operations that depend on the login state.
For this situation, we designed a state machine tool: Status
Based on the state machine, we can write code like this:
import { Status } from '@beautywe/plugin-status';
// on app.js
App({
status: {
login: new Status('login');
},
onLaunch() {
session
// Initiate a silent login call
.login()
// Set the state machine to SUCCESS
.then(() = > this.status.login.success())
// Set the state machine to fail
.catch(() = > this.status.login.fail()); }});// on page.js
Page({
onLoad() {
const loginStatus = getApp().status.login;
// Must is used to determine the state, such as waiting for the login, returning if the login succeeds, or throwing if the login fails.
loginStatus().status.login.must(() = > {
// Perform some operations that require login state...}); }});Copy the code
2. Initiate login when the first Login interface is invoked
Further, we see that the deeper node that requires a logon state is when the “logon state backend API” is initiated.
We can then initiate “silent login” while calling the “logon required backend API”, and for concurrent scenarios, let the other requests wait.
Using fly.js as the “web request layer” wrapped in wx.request(), we can do a simple example:
// Initiate a request and indicate that the request requires a logon state
fly.post('https://... ', params, { needLogin: true });
// Handle logic in fly interceptor
fly.interceptors.request.use(async (req)=>{
// When the request requires a logon state
if(req.needLogin ! = =false) {
// The ensureLogin core logic is: check whether you are logged in, if not initiate a login call, if you are logged in, enter the queue to wait for the callback.
await session.ensureLogin();
// After the login succeeds, the token is obtained and sent to the backend using headers.
const token = await session.getToken();
Object.assign(req.headers, { [AUTH_KEY_NAME]: token });
}
return req;
});
Copy the code
3.1.3 User-defined fault tolerance for login state expiration
When the custom login state expires, the backend needs to return a specific status code, such as AUTH_EXPIRED and AUTH_INVALID.
The front-end can listen for the status code of all requests in the “network request layer”, and then initiate a login state refresh, and then replay the failed request:
// Add a response interceptor
fly.interceptors.response.use(
(response) = > {
const code = res.data;
// The login state is expired or invalid
if(['AUTH_EXPIRED'.'AUTH_INVALID'].includes(code) ) {
// Refresh the login state
await session.refreshLogin();
// Then re-initiate the request
returnfly.request(request); }})Copy the code
If multiple requests are made concurrently, all of which return a logon invalid status code, the above code will be executed multiple times.
We need to do some special fault tolerance for session.refreshLogin() :
- Request lock: Only one in-process network request is allowed at a time.
- Wait queue: After a request is locked, all calls to this method are pushed into a queue and shared by the network until the request completes.
- Circuit breaker: If it is called several times in a short period of time, it stops responding for a period of time, similar to TCP slow start.
Sample code:
class Session {
/ /...
// Refresh the login fuse, repeat for 3 times at most, then fuse, and recover after 5 seconds
refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;
refreshLoginFuseLocked = false;
refreshLoginFuseRestoreTime = 5000;
// Fuse control
refreshLoginFuse(): Promise<void> {
if (this.refreshLoginFuseLocked) {
return Promise.reject('Refresh login - Fuse has been blown, please wait');
}
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('Refresh login - Fuse disengage');
}, this.refreshLoginFuseRestoreTime);
return Promise.reject('Refresh login - fuse blown!! '); }}// And sends back to the callback queue
refreshLoginQueueMaxLength = 100;
refreshLoginQueue: any[] = [];
refreshLoginLocked = false;
// Refresh the login state
refreshLogin(): Promise<void> {
return Promise.resolve()
// Callback queue + fuse control
.then(() = > this.refreshLoginFuse())
.then(() = > {
if (this.refreshLoginLocked) {
const maxLength = this.refreshLoginQueueMaxLength;
if (this.refreshLoginQueue.length >= maxLength) {
return Promise.reject('refreshLoginQueue exceeds capacity:${maxLength}`);
}
return new Promise((resolve, reject) = > {
this.refreshLoginQueue.push([resolve, reject]);
});
}
this.refreshLoginLocked = true;
})
// Initiate the login process after passing the front control
.then(() = > {
this.clearSession();
wx.showLoading({ title: 'Refresh in Logon state'.mask: true });
return this.login()
.then(() = > {
wx.hideLoading();
wx.showToast({ icon: 'none'.title: 'Login successful' });
this.refreshLoginQueue.forEach(([resolve]) = > resolve());
this.refreshLoginLocked = false;
})
.catch(err= > {
wx.hideLoading();
wx.showToast({ icon: 'none'.title: 'Login failed' });
this.refreshLoginQueue.forEach(([, reject]) = > reject());
this.refreshLoginLocked = false;
throw err;
});
});
// ...
}
Copy the code
3.1.4 Fault tolerance of wechat session_key expiration
After the above “silent login”, the wechat server will issue a session_key to the back end, which will be used when we need to obtain wechat open data.
Session_key is time-sensitive. The following is an excerpt from wechat’s official description:
Session key session_key validity
If the developer encounters a signature verification failure or decryption failure due to an incorrect session_key, please pay attention to the following notes related to session_key.
- When wx.login is invoked, the user’s session_key may be updated, making the old session_key invalid. (The refresh mechanism has the shortest period. If the same user invokes wx.login several times in a short period, the session_key may not be refreshed every time.) Developers should only call wx.login when it is clear that they need to log back in and update the session_key stored on the server through auth.code2session.
- Wechat will not inform developers of the expiry date of session_key. We renew the session_key based on the user’s behavior with the applet. The more frequently users use applets, the longer the session_key validity period.
- If the session_key is invalid, the developer can obtain the valid session_key by executing the login process again. The wx.checkSession interface can be used to verify that the session_key is valid, thus avoiding repeated login processes by applets.
- When implementing a custom login state, developers can use the session_key validity period as their own login state validity period or implement a custom validity policy.
Translated into two simple sentences:
session_key
Timeliness is controlled by wechat and developers are unpredictable.wx.login
Could lead tosession_key
Expired and can be used before the interface is usedwx.checkSession
Check it out.
For the second point, we found by experiment that wx.checkSession will return true occasionally when session_key has expired
There is also related feedback from the community that has not been addressed:
- The small program decrypts the phone number. After a short interval, checkSession: OK, but decryption fails
- Wx. checkSession is valid but failed to decrypt data
- CheckSession Checks that the session_key is valid, but fails to decrypt the mobile phone number
So the conclusion is:wx.checkSession
Reliability is not 100%.
Based on the above, we need to do some fault tolerance for session_key expiration:
- Initiate the need to use
session_key
Do it once before you askwx.checkSession
Operation, refresh login state if failed. - The back-end using
session_key
Failure to decrypt open data returns a specific error code (e.g.DECRYPT_WX_OPEN_DATA_FAIL
), the front end refreshes the login state.
Sample code:
// Define an operation to check the validity of session_key
const ensureSessionKey = async() = > {const hasSession = await new Promise(resolve= > {
wx.checkSession({
success: () = > resolve(true),
fail: () = > resolve(false)}); });if(! hasSession) { logger.info('sessionKey expired, refresh login state ');
// Follow the refresh logon logic mentioned above
return session.refreshLogin();
}
return Promise.resolve();
}
// Make sure session_key is up to date when making a request (take fly.js as the web request layer example)
const updatePhone = async (params) => {
await ensureSessionKey();
const res = await fly.post('https://xxx', params);
}
// Add a response interceptor to listen for network requests to return
fly.interceptors.response.use(
(response) = > {
const code = res.data;
// The login state is expired or invalid
if(['DECRYPT_WX_OPEN_DATA_FAIL'].includes(code)) {
// Refresh the login state
await session.refreshLogin();
// Since the encrypted data in the encryption scenario is generated by the user's click, the session_key may have changed, requiring the user to click again.
wx.showToast({ title: 'Network error, please try again later'.icon: 'none'}); }})Copy the code
3.2 Implementation of Authorization
3.2.1 Component separation and design
In terms of access to user information and mobile phone number, wechat uses to allow users to click authorization.
So to make the code more decoupled, let’s design three components:
<user-contaienr getUserInfo="onUserInfoAuth">
: Package click interactive, through<slot>
Supports custom UI for click areas.<phone-container getPhonenNmber="onPhoneAuth">
And:<user-container>
In the same way.<auth-flow>
: Combination based on service requirements<user-container>
,<phone-container>
Combination to define different authorization processes.
Take the process for the opening business scenario, which has the following requirements:
- There are multiple steps.
- If it breaks in the middle, it can be used indirectly.
- In some scenarios, only User information authorization is required, but mobile phone number is not required.
Then the authorization stage can be divided into three layers:
// The user login stage
export enum AuthStep {
// Phase 1: Only login state, no user information, no mobile phone number
ONE = 1.// Phase 2: there is user information, but no mobile phone number
TWO = 2.// Stage 3: There is user information, there is mobile phone number
THREE = 3,}Copy the code
The AuthStep progression is irreversible, and we can define a nextStep function to encapsulate the AuthStep update logic. For external use, just mindlessly call the nextStep method and wait for the callback result.
Sample pseudocode:
// auth-flow component
Component({
// ...
data: {
// By default, only phase two needs to be reached.
mustAuthStep: AuthStep.TWO
},
// The phase that needs to be reached to allow temporary changes to components.
setMustAuthStep(mustAuthStep: AuthStep) {
this.setData({ mustAuthStep });
},
// Based on the user's current information, calculate that the user is in the authorization phase
getAuthStep() {
let currAuthStep;
// No user information, still in the first step
if(! session.hasUser() || ! session.hasUnionId()) { currAuthStep = AuthStepType.ONE; }// No cell phone number, still in step 2
if(! session.hasPhone()) { currAuthStep = AuthStepType.TWO; }// Both, in step 3
currAuthStep = AuthStepType.THREE;
return currAuthStep;
}
// Initiate the next authorization, if all completed, return success.
nextStep(e) {
const { mustAuthStep } = this.data;
const currAuthStep = this.updateAuthStep();
// Authorization is complete
if (currAuthStep >= mustAuthStep || currAuthStep === AuthStepType.THREE) {
// Update the global authorization state machine, broadcast messages to subscribers.
return getApp().status.auth.success();
}
// Step 1: Update user information
if (currAuthStep === AuthStepType.ONE) {
// The ciphertext information is available
if (e) session.updateUser(e);
// Update to view layer, display corresponding UI, wait to obtain user information
else this.setData({ currAuthStep });
return;
}
// Step 2: Update your mobile phone information
if (currAuthStep === AuthStepType.TWO) {
// There is ciphertext information, and the mobile number is updated
if (e) this.bindPhone(e);
// No ciphertext message is displayed
else this.setData({ currAuthStep });
return;
}
console.warn('auth. NextStep mistakes', { currAuthStep, mustAuthStep });
},
// ...
});
Copy the code
So our
can make different UI presentations based on currAuthStep and mustAuthStep. Note that the nextStep(e) function is connected when using
and
Sample pseudocode:
<view class="auth-flow">
<! -- Authorization completed -->
<block wx:if="{{currAuthStep === mustAuthStep || currAuthStep === AuthStep.THREE}}">
<view>Authorization completed</view>
</block>
<! -- Not authorized, first step: authorized user information -->
<block wx:elif="{{currAuthStep === AuthStep.ONE}}">
<user-container bind:getuserinfo="nextStep">
<view>Authorized User Information</view>
</user-container>
</block>
<! -- Not authorized, step 2: Authorized mobile phone number -->
<block wx:elif="{{currAuthStep === AuthStep.TWO}}">
<phone-container bind:getphonenumber="nextStep">
<view>Authorized Mobile phone Number</view>
</phone-container>
</block>
</view>
Copy the code
3.2.2 Processing of permission interception
At this point, we have the component < auth-Flow > that is used to host the authorization process, so it is time to decide when to use it.
Let’s comb through the scenarios that require authorization:
-
Click a button, for example, to buy an item.
In this scenario, authorization is usually done through a pop-up window, which the user can choose to disable.
-
View a page, for example, visit the personal Center.
For this scenario, we can intercept and pop-up when clicking to jump to a page. But such a disadvantage is that the jump to the target page may be a lot of places, each intercept, inevitably will be wrong. And when the target page as a “small program landing page”, it can not be avoided.
At this point, we can complete the authorization process by redirecting to the authorization page, and then come back.
So we define an enumeration variable:
// Display of authorization
export enum AuthDisplayMode {
// in popover form
POPUP = 'button'.// in page form
PAGE = 'page',}Copy the code
We could design a mustAuth method that controls authorization when a button is clicked or when a page loads.
Examples of pseudocode:
class Session {
// ...
mustAuth({
mustAuthStep = AuthStepType.TWO, // LEVEL that requires authorization. By default, user information needs to be obtained
popupCompName = 'auth-popup'.// Authorize the id of the popover component
mode = AuthDisplayMode.POPUP, // Defaults to popover mode} = {}) :Promise<void> {
// If the current authorization step reached the standard, success is returned
if (this.currentAuthStep() >= mustAuthStep) return Promise.resolve();
// Try to get the
component instance of the current page
const pages = getCurrentPages();
const curPage = pages[pages.length - 1];
const popupComp = curPage.selectComponent(` #${popupCompName}`);
// The component does not exist or the specified page is displayed, jump to the authorization page
if(! popupComp || mode === AuthDisplayMode.PAGE) {const curRoute = curPage.route;
// Go to the authorization page, add the route to the current page, and return to the current page after the authorization is complete.
wx.redirectTo({ url: `authPage? backTo=The ${encodeURIComponent(curRoute)}` });
return Promise.resolve();
}
// Set the authorization LEVEL, and then call the nextStep method of
for further authorization.
popupComp.setMustAuthStep(mustAuthStep);
popupComp.nextStep();
// Wait for a successful callback or a failed callback
return new Promise((resolve, reject) = > {
const authStatus = getApp().status.auth;
authStatus.onceSuccess(resolve);
authStatus.onceFail(reject);
});
}
// ...
}
Copy the code
Then we can intercept authorization when a button is clicked, or when a page is loaded:
Page({
onLoad() {
session.mustAuth().then(() = > {
// Start the initialization page...
});
}
onClick(e) {
session.mustAuth().then(() = > {
// Start processing the callback logic...}); }})Copy the code
Of course, if the project uses TS or supports the ES7 Decorator feature, we can provide a Decorator version for mustAuth:
export function mustAuth(option = {}) {
return function(_target, _propertyName, descriptor,) {
// Hijack the target method
const method = descriptor.value;
// Override the target method
descriptor.value = function(. args: any[]) {
return session.mustAuth(option).then(() = > {
// After login, replay the original method
if (method) return method.apply(this, args);
});
};
};
}
Copy the code
Then the way to use it is simpler:
Page({
@mustAuth();
onLoad() {
// Start the initialization page...
}
@mustAuth();
onClick(e) {
// Start processing the callback logic...}});Copy the code
3.3. Sorting out front-end and back-end interaction protocols
As a reusable applet login scheme, it is necessary to define the front and back end interaction protocols.
Then the whole login process, the need for the interface is as follows:
-
SilentLogin silentLogin
- The arguments:
- Code: from wx. The login ()
- Reference:
- Token: user-defined login status certificate
- UserInfo: indicates the user information
- Description:
- The back end uses code to exchange the user id with the wechat client, and then registers and logs in the user, returning to the custom login state
token
To the front token
The front end stores it and takes it with every request- UserInfo must be included
nickname
andphone
Field, the front end is used to calculate the authorization phase of the current user. Of course the recording of this state can be put in the back end, but we think it’s more flexible to put it in the front end.
- The back end uses code to exchange the user id with the wechat client, and then registers and logs in the user, returning to the custom login state
- The arguments:
-
UpdateUser information updateUser
- The arguments:
- Nickname: nickname of the user
- Encrypt: Wechat open data related
iv
.encryptedData
- And other non-essential fields such as gender and address
- Reference:
- UserInfo: indicates the updated user information
- Description:
- The backend decrypts wechat open data and obtains hidden data, such as:
unionId
Etc. - Backend support updates include
nickname
And other basic user information. - The front end updates the userInfo information to
session
Is used to calculate the authorization phase.
- The backend decrypts wechat open data and obtains hidden data, such as:
- The arguments:
-
Update the user’s mobile phone number updatePhone
- The arguments:
- Encrypt: Wechat open data related
iv
.encryptedData
- Encrypt: Wechat open data related
- Reference:
- UserInfo: indicates the updated user information
- Description:
- The backend decrypts the open office, obtains the mobile phone number, and updates it to the user information.
- The front end updates the userInfo information to
session
Is used to calculate the authorization phase.
- The arguments:
-
Unbind the phone number unbindPhone
- The ginseng: –
- Participation: –
- Note: If the user’s mobile phone number is unbound successfully, use the protocol defined by the service.
-
Login logout
-
The ginseng: –
-
Participation: –
-
Note: The back-end active expired login state, successful or not, go to the service defined protocol.
-
5. Structure diagram
Finally, let’s comb through the overall “login service” architecture diagram:
The generic service provided by the combination of “login service” and “underlying construction”, the business layer only needs to customize the authorization flow
according to the product requirements, which can satisfy most scenarios.
6. Summary
This article expands through some common login authorization scenarios to describe the details.
The concepts of “login” and “authorization” are sorted out.
Then it introduces some key technologies for “login” :
- Silent login
- Processing the asynchronous status of silent login
- Custom fault tolerant handling of login state expiration
- WeChat
session_key
Expired fault tolerant handling
For “authorization”, there is logic to design the UI part, which also involves component splitting:
- Component separation and design
- Processing of permission interception
Then, the back-end interfaces that the login authorization scheme depends on are sorted out, and the simplest reference protocol is given.
Finally, from the point of view of “aiming at settling a common applet login solution and service”, we combed the layers of architecture.
- Business Customization layer
- Login service layer
- Construction of the underlying
Reference 7.
- Fly. Js’s official website
- Wechat official document – Authorization
- Wechat official document – server access to open data
- Official wechat community
- The small program decrypts the phone number. After a short interval, checkSession: OK, but decryption fails
- Wx. checkSession is valid but failed to decrypt data
- CheckSession Checks that the session_key is valid, but fails to decrypt the mobile phone number
Eight open source.
In response to the needs of your audience, these dynamics led me to “step forward” and encapsulate some reusable solutions:
- Concurrent processing: Method Fuse – Function Fuse
- A Concurrent Merger – a Concurrent Merger is called