import { NextResponse } from 'next/server' import CryptoJS from 'crypto-js' import { codeStore } from '@/utils/code-store' const CODE_CRYPTO_KEY = 'k#8Mp$2Qr&9Tz@4W' const SHARED_API = ( process.env.NEXT_PUBLIC_SHARED_API_PATH || 'http://172.16.115.31:6610' ).replace(/\/+$/, '') function decrypt(encrypted: string): string { try { const bytes = CryptoJS.AES.decrypt(encrypted, CODE_CRYPTO_KEY) return bytes.toString(CryptoJS.enc.Utf8) } catch { return encrypted } } function generateCode(): string { return Math.random().toString(36).substring(2, 10) + Date.now().toString(36) } async function callBasisApi(path: string, body: object) { const url = `${SHARED_API}${path}` console.log('[sso-mock] →', url) const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) const text = await res.text() let data: any try { data = JSON.parse(text) } catch { throw new Error(`后端返回非 JSON [${res.status}]: ${text.slice(0, 200)}`) } return data } // ─── POST /api/login ─── // 与 uirefbase 保持一致:客户端发 JSON.stringify(encrypt(...)) // req.json() 去掉外层引号得到加密字符串,decrypt 解密得到原始 JSON export async function POST(req: Request) { try { const decryptData = await req.json() // JSON 字符串 → 去掉引号 → 加密原文 const body = JSON.parse(decrypt(decryptData)) const type = body?.type console.log('[sso-mock] login | type:', type, '| body keys:', Object.keys(body || {})) if (!type) { return NextResponse.json({ error: '缺少 type 字段', debug_type: typeof type }) } let res: any if (type === 'account') { res = await callBasisApi('/api/v1/basis/login/account', { account: body.account, password: body.password, abbr: body.abbr, }) } else if (type === 'phone') { res = await callBasisApi('/api/v1/basis/user/phone/login', { phone: body.phone, verify_code: body.verify_code, tntkey: body.tntkey, }) } else if (type === 'feishu') { res = await callBasisApi('/api/v1/basis/login/feishu', { code: body.code, redirect_uri: body.redirect_uri, tenant_abbr: body.tenant, }) } else { console.error('[sso-mock] 未知 type:', type) return NextResponse.json({ error: `不支持的登录方式: ${type}` }) } console.log('[sso-mock] backend res.code:', res?.code) // 后端业务码非 200 视为失败,直接返回错误,不生成 code if (res?.code !== 200) { const message = res?.message || res?.msg || '登录失败' console.log('[sso-mock] backend error:', message) return NextResponse.json({ error: message }) } const user = res.data?.user if (!user || !user.account) { console.log('[sso-mock] backend returned 200 but no valid user') return NextResponse.json({ error: '后端未返回有效用户信息' }) } const tenant = user?.tntkey || body.abbr || 'coowa' const user_info = user const rbac = res?.data?.rbac || { data: [] } const token = res.data?.access_token || '' const responseData: any = { tenant, user_info, rbac, token } // SSO 模式:仅当 client_id + client_redirect_uri 都存在时生成 code const client_id = body.client_id const client_redirect_uri = body.client_redirect_uri if (client_id && client_redirect_uri) { const code = generateCode() codeStore.set(code, { user: user_info, expires: Date.now() + 5 * 60 * 1000, }) responseData.code = code console.log('[sso-mock] code generated →', code) } return NextResponse.json(responseData) } catch (err: any) { console.error('[sso-mock] login error:', err.message) return NextResponse.json({ error: err?.message || '登录失败' }) } }