Session
This page has not been translated into English yet. The Russian original is below.
Вход в аккаунт: пара токенов, её обновление и сведения о том, кто вошёл. Читает состояние
сам элемент
, пишет — пространство
session.*
, тем же разделением, что
`Records`
/
records.add
: у выражения REEEL нет левой части, которой можно присвоить.
Тип:
multi-child
(генератор, поддерживает слоты жизненного цикла)
Требует рантайм:
49 (
expiresField
и
signedOutRoute
— 50)
@email:""
@password:""
Session baseUrl:"https://api.example.com"
loginPath:"/auth/login" refreshPath:"/auth/refresh" mePath:"/auth/me"
accessField:"access_token" refreshField:"refresh_token" expiresField:"expires_in"
user:@user signedIn:@in status:@st error:@err
CircularProgressIndicator id:loading
Column id:signedOut
TextField value:$email
TextField value:$password obscureText:true
ElevatedButton onPressed:(){session.signIn(email:email, password:password)}
Text $strings.authSignIn
Column id:ready
Text {user['email'] ?? ""}
Ни одного умолчания про конкретный бэкенд. Пути и имена полей задаются каждый раз: элемент, знающий один сервер, был бы не возможностью формата, а частной деталью в общем словаре. Многословность лечится на уровне проекта — объявите макрос со своими значениями и зовите его.
Параметры
| Параметр | Тип | Default | Описание |
|---|---|---|---|
baseUrl
|
string | — | Адрес API; к нему приписываются пути ниже |
loginPath
|
string | — | Куда уходит вход |
refreshPath
|
string | — | Куда уходит обновление токена |
mePath
|
string | — | Кто вошёл; спрашивается, только когда срок неизвестен |
logoutPath
|
string? | — | Необязательный; выход состоится и без него |
accessField
|
string |
access_token
|
Имя поля с токеном доступа в ответе |
refreshField
|
string |
refresh_token
|
Имя поля с токеном обновления |
expiresField
|
string |
expires_in
|
Имя поля со сроком жизни В СЕКУНДАХ |
refreshRotates
|
bool |
true
|
Заменяется ли refresh при обновлении |
storageKey
|
string |
session
|
Под каким ключом хранится пара — два сервиса не затрут друг друга |
signedOutRoute
|
string? | — | Куда уводить невошедшего (только веб-сайты) |
Выходы
| Выход | Значение |
|---|---|
user:@user
|
ответ
mePath
или
null
|
signedIn:@in
|
bool |
status:@st
|
checking
,
signedOut
или
signedIn
|
error:@err
|
код последнего отказа или
null
|
Три состояния, а не два
Пока сохранённая пара проверяется,
ещё не известно
, вошёл ли человек. Свести это к «не вошёл» — значит мигнуть формой входа тому, кто уже вошёл, — на каждом запуске. Поэтому у
status
есть
checking
, а слоты по
id:
повторяют то же:
loading
,
signedOut
,
ready
.
Коды ошибок
error
несёт имя состояния, а не фразу: какими словами это показать и на каком языке — решает разметка через
$strings
.
| Код | Что случилось | Что с этим делать |
|---|---|---|
badCredentials
|
вход отвергнут | сказать об этом, набранное сохранить |
signInFailed
|
при входе сломалось что-то другое | предложить повторить |
refreshRejected
|
токен обновления мёртв — сессия кончилась | показать вход |
accountBlocked
|
отказано АККАУНТУ: блокировка, неподтверждённая почта | сказать, какая именно; повторный вход не поможет |
refreshUnavailable
|
подвела сеть или сервер — про токен это не говорит НИЧЕГО | сессия сохранена, можно повторить |
Последние два различаются потому, что лечатся противоположно. Потерянный пакет — не мёртвый токен: приняв одно за другое, приложение выкидывает человека из аккаунта, который был цел.
Подъём без запроса
Разрешённая сессия сохраняется целиком — пара, срок и пользователь. На следующем запуске неистёкший срок разрешает её без единого запроса ; истёкший сразу обновляют, а не спрашивают «кто я», чтобы услышать 401. Спрашивают только там, где бэкенд срока не сообщает.
Срок берётся из ответа (
expiresField
), а не разбором токена: токен может быть непрозрачным, и элемент ничего не знает о том, какой сервер ему достался.
Чем платим: отозванный на сервере токен (выход с другого устройства, блокировка) заметят не раньше, чем первый настоящий запрос вернёт 401 — тем путём, который для этого и написан.
Пространство
session.*
| Метод | Описание |
|---|---|
session.signIn(…)
|
именованные аргументы — это и есть тело запроса: имена полей у каждого бэкенда свои |
session.signOut()
|
пара удаляется, даже если сказать серверу не удалось |
session.refresh()
|
проверить сейчас; нужно редко — протухший токен обновляется сам |
Звать из обработчика:
onPressed:(){session.signIn(…)}
. Голое
{session.signIn(…)}
— выражение-значение, и оно сработает один раз при появлении экрана.
На сайте
Тот же элемент работает в
kind:website
, с двумя отличиями.
Разделы кабинета живут
отдельными страницами
с настоящими адресами, а
signedOutRoute:"/signin"
уводит туда того, про кого выяснилось, что он не вошёл. Это удобство, а не разграничение: разметку страницы отдадут кому угодно, приватного в ней нет, а данные закрывает сервер.
Обновление токена — одно на все вкладки : платформы, ротирующие refresh, считают повторно предъявленный токен компрометацией и аннулируют всю семью — то есть две вкладки, обновившиеся разом, выкидывают человека из аккаунта в обеих. Рантайм это обеспечивает сам.