oa-email-code-login 实现邮箱验证码登录

这个提交包含在:
2026-05-27 06:49:58 +08:00
父节点 afa03c0b71
当前提交 7f96cc0379
共修改 21 个文件,包含 1027 行新增和 45 行删除
+16 -1
查看文件
@@ -21,6 +21,7 @@ import { changePassword as changePasswordApi } from "../api/auth";
import { clearPwaRuntimeCaches } from "../pwa";
import {
fetchCurrentEmployee,
loginWithEmailCode as loginWithEmailCodeRequest,
loginWithPassword,
logoutSession,
refreshSession,
@@ -37,6 +38,7 @@ type OfflineAuthSnapshot = {
type AuthContextValue = AuthState & {
login: (identifier: string, password: string) => Promise<{ mustChangePassword: boolean }>;
loginWithEmailCode: (email: string, code: string) => Promise<{ mustChangePassword: boolean }>;
changePassword: (oldPassword: string, newPassword: string) => Promise<void>;
logout: () => Promise<void>;
bootstrapByRefresh: () => Promise<void>;
@@ -426,6 +428,18 @@ export function AuthProvider({ children }: PropsWithChildren) {
[commitAuthenticatedUser, scheduleProactiveRefresh],
);
const loginWithEmailCode = useCallback(
async (email: string, code: string) => {
const result = await loginWithEmailCodeRequest({ email, code });
const mustChangePassword = Boolean(result.mustChangePassword);
const me = await fetchCurrentEmployee(result.accessToken);
commitAuthenticatedUser(result.accessToken, me, mustChangePassword);
scheduleProactiveRefresh(result.expiresIn);
return { mustChangePassword };
},
[commitAuthenticatedUser, scheduleProactiveRefresh],
);
const changePassword = useCallback(
async (oldPassword: string, newPassword: string) => {
const result = await changePasswordApi({ oldPassword, newPassword });
@@ -525,6 +539,7 @@ export function AuthProvider({ children }: PropsWithChildren) {
() => ({
...state,
login,
loginWithEmailCode,
changePassword,
logout,
bootstrapByRefresh,
@@ -532,7 +547,7 @@ export function AuthProvider({ children }: PropsWithChildren) {
clearSession,
offlineAccessMode,
}),
[bootstrapByRefresh, changePassword, clearSession, login, logout, offlineAccessMode, refreshMe, state],
[bootstrapByRefresh, changePassword, clearSession, login, loginWithEmailCode, logout, offlineAccessMode, refreshMe, state],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
+6
查看文件
@@ -1,4 +1,5 @@
import { apiRequestData } from "../api/http";
import { verifyEmailLoginCode } from "../api/auth";
import type { LoginRequest, LoginResponse, MeResponse } from "../api/types";
import { getDeviceFingerprint } from "./deviceFingerprint";
@@ -32,6 +33,11 @@ export async function loginWithPassword(payload: LoginRequest) {
});
}
export async function loginWithEmailCode(payload: { email: string; code: string }) {
resetRefreshSessionCache();
return verifyEmailLoginCode(payload);
}
async function requestRefreshSession() {
return apiRequestData<LoginResponse>("/api/auth/refresh", {
method: "POST",