Next.js + Mantine mock SSO service providing account/password, phone verify-code, and Feishu QR login. Issues a one-time sso_code that the external app exchanges for user info. Includes: - Feishu callback fix: guard against duplicate/concurrent /api/login submissions of the same single-use authorization code (feishuLogin once-guard + memoized onLoginSuccess to stop effect re-fire). - ADAPTATION_GUIDE.md: how to switch from the in-memory code store to the real backend auth/index + inner_get_user_info endpoints. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42 lines
915 B
TypeScript
42 lines
915 B
TypeScript
/**
|
||
* Mock SSO 认证码存储(内存)
|
||
* 生产环境应使用 Redis 等持久化方案
|
||
*/
|
||
|
||
interface MockUser {
|
||
id: string
|
||
account: string
|
||
name: string
|
||
phone: string
|
||
avatar: string
|
||
roles: string[]
|
||
}
|
||
|
||
interface CodeEntry {
|
||
user: MockUser
|
||
expires: number
|
||
}
|
||
|
||
// 使用 globalThis 避免 Next.js 开发模式下 HMR 导致数据丢失
|
||
const globalForCodeStore = globalThis as unknown as {
|
||
__ssoCodeStore: Map<string, CodeEntry> | undefined
|
||
}
|
||
|
||
if (!globalForCodeStore.__ssoCodeStore) {
|
||
globalForCodeStore.__ssoCodeStore = new Map()
|
||
}
|
||
|
||
export const codeStore = globalForCodeStore.__ssoCodeStore!
|
||
|
||
// 定时清理过期 code(仅在非 edge 环境)
|
||
if (typeof setInterval !== 'undefined') {
|
||
setInterval(() => {
|
||
const now = Date.now()
|
||
for (const [key, val] of codeStore) {
|
||
if (val.expires < now) codeStore.delete(key)
|
||
}
|
||
}, 60_000)
|
||
}
|
||
|
||
export type { MockUser, CodeEntry }
|