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>
57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
import CryptoJS from 'crypto-js'
|
|
|
|
const SECRET_KEY = 'mock-sso-secret-key-2024'
|
|
const TOKEN_KEY = 'sso_token'
|
|
const USER_KEY = 'sso_user'
|
|
|
|
export const encrypt = (data: string) => {
|
|
try {
|
|
return CryptoJS.AES.encrypt(data, SECRET_KEY).toString()
|
|
} catch {
|
|
return data
|
|
}
|
|
}
|
|
|
|
export const decrypt = (data: string) => {
|
|
try {
|
|
const bytes = CryptoJS.AES.decrypt(data, SECRET_KEY)
|
|
return bytes.toString(CryptoJS.enc.Utf8)
|
|
} catch {
|
|
return data
|
|
}
|
|
}
|
|
|
|
export const setAuth = (token: string, user: object) => {
|
|
if (typeof window === 'undefined') return
|
|
localStorage.setItem(TOKEN_KEY, encrypt(token))
|
|
localStorage.setItem(USER_KEY, encrypt(JSON.stringify(user)))
|
|
}
|
|
|
|
export const getToken = (): string | null => {
|
|
if (typeof window === 'undefined') return null
|
|
const encrypted = localStorage.getItem(TOKEN_KEY)
|
|
if (!encrypted) return null
|
|
return decrypt(encrypted)
|
|
}
|
|
|
|
export const getUser = (): object | null => {
|
|
if (typeof window === 'undefined') return null
|
|
const encrypted = localStorage.getItem(USER_KEY)
|
|
if (!encrypted) return null
|
|
try {
|
|
return JSON.parse(decrypt(encrypted))
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export const clearAuth = () => {
|
|
if (typeof window === 'undefined') return
|
|
localStorage.removeItem(TOKEN_KEY)
|
|
localStorage.removeItem(USER_KEY)
|
|
}
|
|
|
|
export const isAuthenticated = (): boolean => {
|
|
return !!getToken()
|
|
}
|