Добро пожаловать в мой блог, чтобы читать:«Внешний дизайн и реализация входа в апплет WeChat»"
Введение
Цель такого сложного дизайна входа/регистрации, конечно же, состоит в том, чтобы сделать эту базовую возможность приложения достаточно надежной, чтобы избежать блокировки всего сайта.
В то же время необходимо полностью продумать, как развязать и инкапсулировать, При разработке новых небольших программ это может ускорить демультиплексирование и избежать повторного майнинга ям.
Вход в систему и регистрация этого модуля подобны айсбергу.Мы думали, что это «введите пароль учетной записи, и вход завершен», но на самом деле есть разные вопросы, которые необходимо учитывать.
Здесь я хотел бы поделиться со всеми вами некоторым опытом проектирования и идеями, которые были накоплены после недавнего завершения небольшого модуля входа/регистрации программы.
2. Бизнес-сценарий
В процессе просмотра мини-программ пользователям часто необходимо получить некоторую базовую информацию о пользователях из-за потребностей бизнеса.
- псевдоним WeChat
- Номер телефона WeChat
Разные продукты имеют разные требования к информации для пользователей и разные процессы авторизации.
Первый распространен в системах электронной коммерции.Когда пользователь покупает продукт, чтобы идентифицировать мультиплатформенную учетную запись пользователя, он часто использует свой номер мобильного телефона для установления контакта.В это время пользователю необходимо авторизоваться номер мобильного телефона.
Во-вторых, чтобы получить базовую инициализацию информации о пользователе, часто необходимо получить дополнительную информацию о пользователе: например, псевдоним WeChat,unionId
и так далее, нужно запрашивать у пользователя авторизацию.
Третий включает в себя первый и второй.
3. Концепция
С целью ускорить общий набор решений и услуг для входа в небольшую программу, давайте проанализируем бизнес и получим переменные.
Перед тем, как заняться техническим проектированием, необходимой ерундой, базовой частотной настройкой некоторых понятий.
2.1 О «Входе»
Логин - это "login" на английском, и соответствующий "logout". Прежде чем войти в систему, вам необходимо иметь учетную запись, вам необходимо «зарегистрироваться» (или зарегистрироваться).
Другими словами, изначально в продукте не было функции входа/регистрации, и она стала доступна постепенно, когда ею воспользовалось все больше людей. Для нужд самого продукта необходимо идентифицировать «пользователя».
В реальном обществе у каждого из нас есть удостоверение личности: удостоверение личности. Когда мне было 16 лет, я впервые пошел в бюро общественной безопасности, чтобы получить свое удостоверение личности, я сделал акт «регистрации». Затем я пошел в интернет-кафе, чтобы посидеть в Интернете, взял свое удостоверение личности и выполнил действие «вход в систему».
Таким образом, для Интернета в виртуальном мире таким подтверждением личности является «учетная запись + пароль».
Распространенные способы входа/регистрации:
-
Регистрация пароля учетной записи
На заре Интернета личные почтовые ящики и сотовые телефоны были малодоступны. Поэтому пользователям необходимо самим придумать имя учетной записи.Мы регистрируем учетную запись QQ, которая находится в таком виде.
-
Регистрация адреса электронной почты
Спустя тысячелетие эра компьютерного Интернета быстро распространилась, и мы все создали свои личные почтовые ящики. Кроме того, у QQ есть собственная учетная запись электронной почты. Поскольку почтовый ящик является частным и может передавать информацию, большинство веб-сайтов начинают использовать учетную запись почтового ящика в качестве имени пользователя для регистрации, и в процессе регистрации вам потребуется войти в соответствующий почтовый ящик, чтобы проверить активационное электронное письмо, чтобы подтвердить нашу Владение зарегистрированным адресом электронной почты.
-
Регистрация мобильного номера
После популяризации Интернета смартфоны и мобильный Интернет получили быстрое развитие. Мобильные телефоны также стали незаменимым мобильным устройством для всех, и мобильный Интернет также глубоко интегрировался в современную жизнь каждого человека. Поэтому, по сравнению с почтовым ящиком, текущий номер мобильного телефона более тесно связан с физическим лицом, и появляется все больше и больше мобильных приложений, а также широко используется метод регистрации с использованием номера мобильного телефона в качестве имени пользователя.
К 2020 году количество пользователей WeChat достигнет 1,2 миллиарда. Что ж, учетные записи WeChat, по крайней мере, в Китае, стали «визитной карточкой» нового поколения интернет-мира.
Для апплета WeChat естественно знать идентификатор учетной записи WeChat текущего пользователя. WeChat позволяет небольшим программным приложениям незаметно «входить» в наши небольшие программные приложения без восприятия пользователя.Это то, что мы часто называем «тихим входом».
На самом деле, вход в апплет WeChat по сути такой же, как «единый вход» в традиционные веб-приложения.
- Единый вход: после входа на станции A станции C и B могут выполнить быстрый «тихий вход».
- Вход в апплет WeChat: в WeChat, если вы войдете в свою учетную запись WeChat, вы можете добиться «тихого входа» во всей экосистеме апплета.
Поскольку Http изначально не имеет состояния, основная общая практика отрасли для состояния входа в систему:
- cookie-session: обычно используется в браузерных приложениях.
- токен доступа: обычно используется в небраузерных приложениях, таких как мобильные терминалы.
В апплете WeChat "слой логики JS" не является браузерной средой, естественно нетCookie
, то обычно используютaccess token
Путь.
2.2 Об «авторизации»
Для продуктов, которым необходимо дополнительно получить такую информацию, как псевдоним пользователя, номер мобильного телефона пользователя и т. д. Из соображений конфиденциальности пользователей WeChat требует от пользователей активного согласия на авторизацию. Только приложение апплета может получить эту часть информации, что приводит к взаимодействию популярного апплета «информация авторизованного пользователя» и «авторизованный номер мобильного телефона».
Из-за разной степени конфиденциальности различной пользовательской информации мини-программы WeChat обеспечивают «авторизацию» для различной пользовательской информации по-разному:
- Вызов конкретного метода API, всплывающее окно авторизации.
- Например, вызов
wx.getLocation()
Если пользователь не авторизован, откроется интерфейс авторизации адреса. - В случае отказа он больше не выскочит,
wx.getLocation()
Вернитесь прямо к неудаче.
- Например, вызов
-
<button open-type="xxx" />
Способ.- Только поддержка: конфиденциальная информация пользователя, номер мобильного телефона пользователя, необходимо сотрудничать с серверной частью для выполнения симметричного шифрования и дешифрования, прежде чем данные могут быть получены.
- Пользователь отказался, нажмите кнопку еще раз, и окно все равно появится.
- пройти через
wx.authorize()
, попросите авторизацию заранее, и вам не нужно снова открывать авторизацию, когда вам нужно будет получить соответствующую информацию позже.
4. Детальный дизайн
Разобравшись с понятиями, разделение наших модулей можно разделить на две части:
-
Авторизоваться: Отвечает за создание сеанса с сервером, этот сеанс реализует автоматический вход в систему и соответствующую обработку отказоустойчивости и т. д. Имя модуля:
Session
-
Разрешить: Отвечает за взаимодействие с пользователями, получение и обновление информации, контроль разрешений и т. д. Модуль называется:
Auth
3.1 Реализация входа в систему
3.1.1 Silent Login.
Официальное решение для входа в систему, предоставляемое WeChat, можно разделить на три этапа:
- проход переднего конца
wx.login()
Получите одноразовый зашифрованный код сертификата и передайте его серверной части. - Бэкэнд передает этот код на сервер WeChat в обмен на уникальный идентификатор пользователя.
openId
и учетные данные авторизацииsession_key
. (Для последующих вызовов специального API на стороне сервера и сервера WeChat см.:Официальная документация WeChat — серверный доступ к открытым данным). - Серверная часть передает учетные данные пользователя, полученные с сервера WeChat, и самостоятельно сгенерированные учетные данные для входа (токен) во внешний интерфейс. Передняя часть сохраняется и переносится в заднюю часть, когда делается следующий запрос, чтобы определить, какой пользователь.
Если вы просто реализуете этот процесс, это довольно просто.
Но для обеспечения надежного процесса входа в систему необходимо знать о других крайних случаях:
-
крупным планом
wx.login()
вызов:из-за
wx.login()
могут иметь непредсказуемые побочные эффекты, такие какsession_key
Недопустимо, что приводит к последующим сбоям в авторизованных сценариях дешифрования. Здесь мы можем предоставитьsession.login()
метод овладенияwx.login()
контроль, и сделать серию инкапсуляции и отказоустойчивой обработки на нем. -
время звонить:
Обычно при запуске приложения (
app.onLaunch()
), чтобы инициировать автоматический вход в систему. Но будет асинхронная проблема, вызванная дизайном жизненного цикла апплета: при загрузке страницы, при вызове внутреннего API, требующего состояния входа, предыдущий асинхронный статический процесс входа может не завершиться, что приведет к сбою запросов. .Конечно, также можно инициировать вызов входа в систему асинхронным блокирующим образом, когда требуется первый вызов интерфейса, требующий состояния входа в систему, что требует хорошо спроектированного уровня интерфейса.
Детальные проектные идеи двух сценариев, упомянутых выше, будут рассмотрены ниже.
-
проблема с параллельными вызовами:
В бизнес-сценарии неизбежно будет несколько кодов, которые должны инициировать вход в систему. В крайних случаях эти несколько кодов будут инициировать вызовы одновременно. Это приведет к тому, что процесс входа в систему будет инициирован несколько раз за короткий промежуток времени, даже если предыдущий запрос не был выполнен. В этом случае мы можем заблокировать первый вызов и дождаться результата последующих вызовов, как и процесс объединения сперматозоида и яйцеклетки.
-
Проблемы с неистекшими звонками:
Если наш статус входа в систему не истек, его можно использовать в обычном режиме.По умолчанию нет необходимости инициировать процесс входа в систему. В это время мы можем проверить, доступно ли состояние входа по умолчанию.Если его нельзя использовать, мы инициируем запрос. Затем вы также можете предоставить аналогичный
session.login({ force: true })
параметры для принудительной инициации входа в систему.
3.1.2 Обработка асинхронного состояния тихого входа в систему
1. Вызывается при запуске приложения
Поскольку в большинстве случаев необходимо полагаться на состояние входа в систему, мы, естественно, подумаем о том, чтобы указать время этого вызова при запуске приложения (app.onLaunch()
) звонить.
Однако из-за собственного процесса запуска апплетаApp
,Page
,Component
Ни одна из функций ловушки жизненного цикла не поддерживает асинхронную блокировку.
Тогда мы легко встретимсяapp.onLaunch
«Процесс входа», инициированный вpage.onLoad
Время еще не завершено, мы не сможем правильно выполнить некоторые операции, зависящие от состояния входа в систему.
В ответ на эту ситуацию мы разработали инструмент конечного автомата:status
На основе конечного автомата мы можем написать такой код:
import { Status } from '@beautywe/plugin-status';
// on app.js
App({
status: {
login: new Status('login');
},
onLaunch() {
session
// 发起静默登录调用
.login()
// 把状态机设置为 success
.then(() => this.status.login.success())
// 把状态机设置为 fail
.catch(() => this.status.login.fail());
},
});
// on page.js
Page({
onLoad() {
const loginStatus = getApp().status.login;
// must 里面会进行状态的判断,例如登录中就等待,登录成功就直接返回,登录失败抛出等。
loginStatus().status.login.must(() => {
// 进行一些需要登录态的操作...
});
},
});
2. Инициировать вход в систему, когда вызывается «первый интерфейс, требующий состояния входа в систему».
Сделав еще один шаг, мы обнаружим, что более глубокие узлы, которым требуется состояние входа, возникают, когда инициируется «внутренний API, требующий состояния входа».
Затем мы можем инициировать «тихий вход» при вызове «серверного API, требующего статуса входа». Для одновременных сценариев хорошо позволить другим запросам подождать некоторое время.
кfly.jsтак какwx.request()
Инкапсулированный «уровень сетевых запросов» в качестве простого примера:
// 发起请求,并表明该请求是需要登录态的
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;
});
3.1.3 Отказоустойчивая обработка истечения пользовательского статуса входа в систему
Когда срок действия пользовательского статуса входа истекает, серверная часть должна вернуть определенный код состояния, например:AUTH_EXPIRED
,AUTH_INVALID
Ждать.
Внешний интерфейс может отслеживать код состояния всех запросов на «уровне сетевых запросов», затем инициировать обновление состояния входа в систему, а затем воспроизводить неудачный запрос:
// 添加响应拦截器
fly.interceptors.response.use(
(response) => {
const code = res.data;
// 登录态过期或失效
if ( ['AUTH_EXPIRED', 'AUTH_INVALID'].includes(code) ) {
// 刷新登录态
await session.refreshLogin();
// 然后重新发起请求
return fly.request(request);
}
}
)
Затем, если одновременно инициируются несколько запросов, каждый из которых возвращает код состояния, указывающий, что состояние входа в систему недействительно, приведенный выше код будет выполняться несколько раз.
мы должныsession.refreshLogin()
Сделайте какую-нибудь особую отказоустойчивость:
- запросить блокировку: Одновременно разрешен только один выполняющийся сетевой запрос.
- очередь ожидания: после блокировки запроса все вызовы этого метода помещаются в очередь, а возвращаемый результат передается после завершения сетевого запроса.
- автоматический выключатель: при многократном вызове в течение короткого промежутка времени перестает отвечать на запросы в течение определенного периода времени, аналогично медленному запуску TCP.
Образец кода:
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;
});
});
// ...
}
3.1.4 Отказоустойчивая обработка истечения срока действия ключа сеанса WeChat
После того, как мы войдем в систему с помощью вышеуказанного «автоматического входа», сервер WeChat выдастsession_key
на бэкэнд, и это будет извлечено при необходимостиОткрытые данные WeChatбудет использоваться, когда .
а такжеsession_key
Это зависит от времени.Ниже приведен отрывок из официального описания WeChat:
сеансовый ключ session_key действительность
Если разработчик столкнулся с ошибкой проверки или расшифровки подписи из-за неправильного ключа session_key, обратите внимание на следующие примечания, относящиеся к session_key.
- wx.loginПри вызове session_key пользователявозможноОн будет обновлен, и старый session_key станет недействительным (механизм обновления имеет самый короткий цикл, если один и тот же пользователь звонит несколько раз за короткое время)wx.login, не каждый вызов вызывает обновление session_key). Разработчики должны звонить только тогда, когда им явно нужно повторно войти в систему.wx.login, прошло во времениauth.code2SessionИнтерфейс обновляет session_key, хранящийся на сервере.
- WeChat не будет информировать разработчиков о сроке действия session_key. Мы обновим session_key в соответствии с поведением пользователя при использовании апплета. Чем чаще пользователь использует апплет, тем дольше действует session_key.
- Когда session_key недействителен, разработчик может получить действительный session_key, повторно выполнив процесс входа в систему. использовать интерфейсwx.checkSessionВы можете проверить, действителен ли session_key, чтобы избежать многократного выполнения апплетом процесса входа в систему.
- Когда разработчики реализуют пользовательское состояние входа в систему, они могут рассмотреть возможность использования периода действия session_key в качестве своего собственного периода действия состояния входа или реализовать собственную стратегию своевременности.
Переводится в два простых предложения:
-
session_key
Своевременность контролируется WeChat, а разработчики непредсказуемы. -
wx.login
может привести кsession_key
Истекает, можно использовать перед использованием интерфейсаwx.checkSession
чек об оплате.
Что же касается второго пункта, то в ходе экспериментов мы обнаружили, что случайныеsession_key
истек,wx.checkSession
вернется вероятностноtrue
Есть также соответствующие отзывы от сообщества, которые не были рассмотрены:
- Апплет расшифровывает номер мобильного телефона, через небольшой промежуток времени чексессия: все в порядке, но расшифровка не удалась
- wx.checkSession работает, но расшифровать данные не удается
- checkSession считает, что session_key не является недействительным, но расшифровка номера мобильного телефона не удалась
Итак, вывод такой:wx.checkSession
Надежность менее 100%.
На основании вышеизложенного нам необходимоsession_key
Срок действия делает некоторую отказоустойчивость:
- Инициировать потребность в использовании
session_key
перед запросом сделать это один разwx.checkSession
Операция в случае сбоя обновляет состояние входа. - использование серверной части
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' });
}
}
)
3.2 Внедрение авторизации
3.2.1 Разделение компонентов и дизайн
Что касается способа получения информации о пользователях и номеров мобильных телефонов, WeChat основан на<button open-type='xxx' />
способ разрешить пользователям активно нажимать авторизованные.
Итак, чтобы сделать код более несвязанным, мы разрабатываем эти три компонента:
-
<user-contaienr getUserInfo="onUserInfoAuth">
: оборачивает взаимодействие щелчка через<slot>
Поддержка пользовательского интерфейса для области щелчка. -
<phone-container getPhonenNmber="onPhoneAuth">
: а также<user-container>
То же самое справедливо. -
<auth-flow>
: Комбинация в соответствии с потребностями бизнеса<user-container>
,<phone-container>
Комбинации для определения различных потоков авторизации.
Взяв в качестве примера процесс бизнес-сценария в начале, к нему предъявляются следующие требования:
- Есть несколько шагов.
- Если он прерывается посередине, его можно подключить оттуда.
- В некоторых сценариях требуется только «Авторизация информации о пользователе», а «Мобильный номер пользователя» не требуется.
Тогда этап авторизации можно разделить на три уровня:
// 用户登录的阶段
export enum AuthStep {
// 阶段一:只有登录态,没有用户信息,没有手机号
ONE = 1,
// 阶段二:有用户信息,没有手机号
TWO = 2,
// 阶段三:有用户信息,有手机号
THREE = 3,
}
AuthStep
Процесс продвижения необратим, мы можем определитьnextStep
функция для инкапсуляции логики обновления AuthStep. Если он используется снаружи, просто называйте его бездумноnextStep
метод, просто дождитесь результата обратного вызова.
Пример псевдокода:
// auth-flow component
Component({
// ...
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) {
// 更新全局的授权状态机,广播消息给订阅者。
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 });
},
// ...
});
тогда наш<auth-flow>
может основываться наcurrAuthStep
а такжеmustAuthStep
Приходите и делайте разные отображения пользовательского интерфейса. Следует отметить, что использование<user-container>
,<phone-container>
подключиться, когдаnextStep(e)
функция.
Пример псевдокода:
<view class="auth-flow">
<!-- 已完成授权 -->
<block wx:if="{{currAuthStep === mustAuthStep || currAuthStep === AuthStep.THREE}}">
<view>已完成授权</view>
</block>
<!-- 未完成授权,第一步:授权用户信息 -->
<block wx:elif="{{currAuthStep === AuthStep.ONE}}">
<user-container bind:getuserinfo="nextStep">
<view>授权用户信息</view>
</user-container>
</block>
<!-- 未完成授权,第二步:授权手机号 -->
<block wx:elif="{{currAuthStep === AuthStep.TWO}}">
<phone-container bind:getphonenumber="nextStep">
<view>授权手机号</view>
</phone-container>
</block>
</view>
3.2.2 Обработка перехвата разрешений
На данный момент мы создали компоненты, используемые для выполнения процесса авторизации.<auth-flow>
, то следующим шагом будет решить, когда его использовать.
Разбираем сценарии, требующие авторизации:
-
Нажмите кнопку, например: купить товар.
Для этого сценария авторизация обычно выполняется через всплывающее окно, и пользователь может закрыть его.
-
Просмотрите страницу, например: посетите персональный центр.
Для этого сценария мы можем перехватывать и обрабатывать всплывающие окна, когда мы нажимаем, чтобы перейти на определенную страницу. Однако недостатком этого является то, что может быть много мест для перехода на целевую страницу, и если каждое из них заблокировано, неизбежно будут сделаны ошибки. И когда целевая страница используется как «посадочная страница мини-программы», этого не избежать.
В это время мы можем завершить процесс авторизации, перенаправив на страницу авторизации, а затем вернуться после завершения.
Затем мы определяем переменную перечисления:
// 授权的展示形式
export enum AuthDisplayMode {
// 以弹窗形式
POPUP = 'button',
// 以页面形式
PAGE = 'page',
}
мы можем разработать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 id="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);
});
}
// ...
}
Затем мы можем выполнить перехват авторизации при нажатии на кнопку или при загрузке страницы:
Page({
onLoad() {
session.mustAuth().then(() => {
// 开始初始化页面...
});
}
onClick(e) {
session.mustAuth().then(() => {
// 开始处理回调逻辑...
});
}
})
Конечно, если проект использует 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);
});
};
};
}
Тогда проще использовать:
Page({
@mustAuth();
onLoad() {
// 开始初始化页面...
}
@mustAuth();
onClick(e) {
// 开始处理回调逻辑...
}
});
3.3 Организация интерфейсных и серверных протоколов взаимодействия
В качестве многоразового решения для входа в апплет, конечно, необходимо определить интерфейсные и внутренние протоколы взаимодействия.
Затем весь набор процесса входа в систему, необходимые интерфейсы следующие:
-
тихий вход
- Входные параметры:
- код: создан wx.login()
- Исходящие параметры:
- токен: пользовательские учетные данные для входа
- userInfo: информация о пользователе
- проиллюстрировать:
- Серверная часть использует код для обмена идентификатором пользователя с клиентом WeChat, затем регистрирует и входит в систему пользователя и возвращается в пользовательское состояние входа.
token
к переднему концу -
token
Фронтенд будет сохранен, и каждый запрос будет приносить его - userInfo должен содержать
nickname
а такжеphone
Поле, используемое внешним интерфейсом для расчета стадии авторизации текущего пользователя. Конечно, запись этого состояния можно разместить в бэкенде, но мы думаем, что будет более гибко, если ее разместить во фронтенде.
- Серверная часть использует код для обмена идентификатором пользователя с клиентом WeChat, затем регистрирует и входит в систему пользователя и возвращается в пользовательское состояние входа.
- Входные параметры:
-
Обновить информацию о пользователе updateUser
- Входные параметры:
- псевдоним: псевдоним пользователя
- шифрование: WeChat, связанные с открытыми данными
iv
,encryptedData
- и другие необязательные поля, такие как гендерный адрес
- Исходящие параметры:
- userInfo: последняя информация о пользователе после обновления
- проиллюстрировать:
- Серверная часть расшифровывает открытые данные WeChat и получает скрытые данные, такие как:
unionId
Ждать - Обновления поддержки серверной части включают
nickname
и другую основную информацию о пользователе. - Внешний интерфейс обновит информацию userInfo до
session
, который используется для расчета фазы авторизации.
- Серверная часть расшифровывает открытые данные WeChat и получает скрытые данные, такие как:
- Входные параметры:
-
Обновить номер телефона пользователя updatePhone
- Входные параметры:
- Шифрование: микроканальные данные, связанные с открытым
iv
,encryptedData
- Шифрование: микроканальные данные, связанные с открытым
- Исходящие параметры:
- userInfo: последняя информация о пользователе после обновления
- проиллюстрировать:
- Серверная часть расшифровывает открытое бюро, получает номер мобильного телефона и обновляет его до информации о пользователе.
- Внешний интерфейс обновит информацию userInfo до
session
, который используется для расчета фазы авторизации.
- Входные параметры:
-
Отвязать номер телефона unbindPhone
- Вход:-
- Исходящие параметры:-
- Описание: серверная часть отменяет привязку номера мобильного телефона пользователя, независимо от того, успешна она или нет, она следует клиентским и внутренним протоколам, определенным бизнесом.
-
войти выйти
-
Вход:-
-
Исходящие параметры:-
-
Описание: Серверная часть активно завершает состояние входа в систему, независимо от того, успешно она или нет, она следует интерфейсным и внутренним протоколам, определенным бизнесом.
-
V. Схема архитектуры
Наконец, давайте разберемся с общей архитектурой «Службы входа»:
Общая услуга, предоставляемая комбинацией «службы входа» и «нижнего построения», бизнес-уровню нужно только настроить процесс авторизации в соответствии с требованиями продукта.<auth-flow>
, что достаточно для большинства сценариев.
6. Резюме
В этой статье подробно описаны некоторые распространенные сценарии авторизации входа.
Разобраны понятия "логин" и "авторизация".
Затем вводятся некоторые ключевые технические реализации для «логина»:
- автоматический вход
- Обработка асинхронного состояния тихого входа в систему
- Отказоустойчивая обработка истечения пользовательского статуса входа в систему
- WeChat
session_key
Отказоустойчивость с истекшим сроком действия
Для «авторизации» будет логика разработки части пользовательского интерфейса, и она также должна включать разделение компонентов:
- Расщепление компонентов и дизайн
- Перехватка органа перехвата
Затем он сортирует внутренние интерфейсы, на которые опирается эта схема авторизации входа, и дает простейший эталонный протокол.
Наконец, с точки зрения «сосредоточения внимания на цели создания общего набора решений и сервисов для входа в небольшую программу», я разобрался со слоями на архитектурном уровне.
- уровень бизнес-настройки
- уровень службы входа в систему
- конструкция первого этажа
7. Ссылка
- официальный сайт fly.js
- Официальная документация WeChat — Авторизация
- Официальная документация WeChat — серверный доступ к открытым данным
- Официальное сообщество WeChat
- Апплет расшифровывает номер мобильного телефона, через небольшой промежуток времени чексессия: все в порядке, но расшифровка не удалась
- wx.checkSession работает, но расшифровать данные не удается
- checkSession считает, что session_key не является недействительным, но расшифровка номера мобильного телефона не удалась
8. Открытый исходный код
В ответ на потребности аудитории эти мотивы побудили меня «шагнуть вперед» и инкапсулировать некоторые повторно используемые решения:
- Параллельная обработка:Предохранитель метода - Предохранитель функции
- Лечение слиянием:Concurrent Merger — одновременное слияние вызовов