feat(auth): add facebook identity psid login
This commit is contained in:
@@ -242,29 +242,60 @@ export const guestLoginActor = fromPromise<LoginStatus, void>(async () => {
|
||||
// ========== 启动 / 恢复时检查登录态 actor(只查不创) ==========
|
||||
|
||||
export const checkAuthStatusActor = fromPromise<LoginStatus, void>(async () => {
|
||||
// 1. 拿 deviceId(不用于 auto-guest-login,仅供后续登录用)
|
||||
await deviceIdentifier.getDeviceId();
|
||||
// 1. 拿启动期可能参与身份同步的本地标识。
|
||||
const deviceId = await deviceIdentifier.getDeviceId();
|
||||
const storage = AuthStorage.getInstance();
|
||||
const asidR = await storage.getAsid();
|
||||
const psidR = await storage.getPsid();
|
||||
const asid = asidR.success ? asidR.data : null;
|
||||
const psid = psidR.success ? psidR.data : null;
|
||||
const authRepo = getAuthRepository();
|
||||
|
||||
// 2. 查业务登录 token:loginToken 和 refreshToken 必须同时存在。
|
||||
if (await hasCompleteBusinessAuthSession(storage)) {
|
||||
const providerR = await storage.getLoginProvider();
|
||||
if (providerR.success && isBusinessLoginProvider(providerR.data)) {
|
||||
return providerR.data;
|
||||
const provider =
|
||||
providerR.success && isBusinessLoginProvider(providerR.data)
|
||||
? providerR.data
|
||||
: ("email" as LoginStatus);
|
||||
|
||||
const bindResult = await authRepo.bindFacebookIdentity({
|
||||
asid: asid ?? undefined,
|
||||
psid: psid ?? undefined,
|
||||
});
|
||||
if (Result.isErr(bindResult)) {
|
||||
log.warn(
|
||||
{ err: bindResult.error.message },
|
||||
"[auth-machine] checkAuthStatusActor: bindFacebookIdentity failed",
|
||||
);
|
||||
}
|
||||
return "email" as LoginStatus;
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
// 3. 外部浏览器深链同步:仅 asid 落地时,用它换业务 token。
|
||||
const asidR = await storage.getAsid();
|
||||
if (asidR.success && asidR.data) {
|
||||
const authRepo = getAuthRepository();
|
||||
const avatarUrlR = await UserStorage.getInstance().getAvatarUrl();
|
||||
const psid = await readPsid();
|
||||
const result = await authRepo.facebookAsidLogin({
|
||||
asid: asidR.data,
|
||||
avatarUrl: avatarUrlR.success ? avatarUrlR.data ?? undefined : undefined,
|
||||
// 3. 有 PSID 时优先让后端用本地绑定关系直接登录;未匹配则返回游客态。
|
||||
if (psid) {
|
||||
const psidLoginResult = await authRepo.facebookPsidLogin({
|
||||
psid,
|
||||
deviceId,
|
||||
bindToGuest: true,
|
||||
});
|
||||
if (Result.isOk(psidLoginResult)) {
|
||||
return psidLoginResult.data;
|
||||
}
|
||||
log.warn(
|
||||
{ err: psidLoginResult.error.message },
|
||||
"[auth-machine] checkAuthStatusActor: facebookPsidLogin failed",
|
||||
);
|
||||
}
|
||||
|
||||
// 4. 无 PSID 或 PSID 直登失败时,继续用 ASID fallback 换业务 token。
|
||||
if (asid) {
|
||||
const avatarUrlR = await UserStorage.getInstance().getAvatarUrl();
|
||||
const result = await authRepo.facebookAsidLogin({
|
||||
asid,
|
||||
avatarUrl: avatarUrlR.success ? avatarUrlR.data ?? undefined : undefined,
|
||||
psid: psid ?? undefined,
|
||||
});
|
||||
|
||||
if (Result.isErr(result)) {
|
||||
@@ -278,13 +309,13 @@ export const checkAuthStatusActor = fromPromise<LoginStatus, void>(async () => {
|
||||
return "facebook" as LoginStatus;
|
||||
}
|
||||
|
||||
// 4. 查 guestToken
|
||||
// 5. 查 guestToken
|
||||
const guestTokenR = await storage.getGuestToken();
|
||||
if (guestTokenR.success && guestTokenR.data) {
|
||||
return "guest" as LoginStatus;
|
||||
}
|
||||
|
||||
// 5. 都没有 → "notLoggedIn"(保持 splash 页面 + 登录入口)
|
||||
// 6. 都没有 → "notLoggedIn"(保持 splash 页面 + 登录入口)
|
||||
return "notLoggedIn" as LoginStatus;
|
||||
});
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ const toAuthErrorMessage = (error: unknown): string =>
|
||||
//
|
||||
// 设计:所有登录/同步流跑完都回 `idle`(带正确 `loginStatus`)。
|
||||
//
|
||||
// 初始化只恢复已有登录态;游客登录必须由用户明确操作触发。
|
||||
// 初始化会恢复已有登录态,并按后端 Facebook identity 规则处理绑定 / PSID 直登。
|
||||
// 普通游客登录仍必须由用户明确操作触发;PSID 未匹配时后端可返回游客态。
|
||||
// ============================================================
|
||||
export const authMachine = setup({
|
||||
types: {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"use client";
|
||||
/**
|
||||
* AuthInit 派发器 —— App 启动时读 storage 同步 loginStatus 到状态机
|
||||
* AuthInit 派发器 —— App 启动时恢复登录态并同步 Facebook identity
|
||||
*
|
||||
* 派发时机:仅 mount 时一次(`useEffect` deps = `[dispatch]`,永远不重跑)。
|
||||
*
|
||||
* 与 <OAuthSessionSync /> 平级:
|
||||
* - AuthStatusChecker: 启动时一次性 init("自己启动时同步")
|
||||
* - AuthStatusChecker: 启动时一次性 init,恢复登录态、绑定 ASID/PSID、尝试 PSID 直登
|
||||
* - OAuthSessionSync: 持续监听 NextAuth session("别人在写")
|
||||
*/
|
||||
import { useEffect } from "react";
|
||||
@@ -25,4 +25,4 @@ export function AuthStatusChecker() {
|
||||
|
||||
// 无 UI
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user