登录注册接入数据库

This commit is contained in:
2026-03-10 17:01:56 +08:00
parent 8561d1debc
commit 4df88ea502
6 changed files with 210 additions and 172 deletions

View File

@@ -166,6 +166,62 @@ const captcha = ref<string>('')
const isLoading = ref<boolean>(false)
/**
* 【核心函数】:登录成功后,多条件校验是否为商家角色
* 优先级: session_uid (auth_id) -> id -> normalized email
*/
const checkMerchantAccess = async (uid: string, rawEmail: string) : Promise<boolean> => {
const email = rawEmail.trim().toLowerCase()
console.log(`🔍 开始校验商家端角色 -> UID: ${uid}, Email: ${email}`)
try {
// 1. 尝试按 auth_id 查询
let res = await supa.from('ak_users').select('role').eq('auth_id', uid).execute()
let dataArray = res.data
if (Array.isArray(dataArray) && dataArray.length > 0) {
const role = (dataArray[0] as UTSJSONObject).getString('role')
console.log('✅ 按 auth_id 匹配成功role:', role)
return role === 'merchant'
}
// 2. 尝试按 id 查询 (兼容老数据)
res = await supa.from('ak_users').select('role').eq('id', uid).execute()
dataArray = res.data
if (Array.isArray(dataArray) && dataArray.length > 0) {
const role = (dataArray[0] as UTSJSONObject).getString('role')
console.log('✅ 按 id 匹配成功role:', role)
return role === 'merchant'
}
// 3. 尝试按 email 兜底查询
if (email !== '') {
res = await supa.from('ak_users').select('role').eq('email', email).execute()
dataArray = res.data
if (Array.isArray(dataArray) && dataArray.length > 0) {
// 如果按邮箱查出来多条,可能存在脏数据,只取第一条并记录日志
if (dataArray.length > 1) {
console.error('⚠️ 警告: 按 email 查到多条 ak_users 记录取第一条校验。Email:', email)
}
const role = (dataArray[0] as UTSJSONObject).getString('role')
console.log('✅ 按 email 匹配成功role:', role)
return role === 'merchant'
}
}
console.error('❌ 未能在 ak_users 中找到该用户的任何记录')
// 查无此人,跑出自定义错误以与普通系统报错区分
throw new Error('NOT_REGISTERED')
} catch (e) {
console.error('❌ 查询角色过程异常:', e)
if (e instanceof Error && e.message === 'NOT_REGISTERED') {
throw new Error('您还没有注册商家端账户,快去注册一个')
}
// 真实的查询异常/RLS异常抛出防止误会为"未注册"
throw new Error('商家身份校验失败,请联系管理员检查用户数据')
}
}
const codeDisabled = ref<boolean>(false)
const codeText = ref<string>('获取验证码')
let codeTimer: number | null = null
@@ -260,8 +316,8 @@ const getCode = async () => {
const handleLogin = async () => {
if (!validateAccount()) return
// 特殊账号处理:admin/admin 直接跳转
if (account.value === 'admin' && password.value === 'admin') {
// 特殊账号处理:仅在测试模式下保留直登逻辑,生产环境强制校验角色
if (IS_TEST_MODE && account.value === 'admin' && password.value === 'admin') {
setIsLoggedIn(true)
const adminProfile = {
id: 'admin',
@@ -301,13 +357,12 @@ const handleLogin = async () => {
if (loginType.value === 0) {
const isEmail = account.value.includes('@')
if (isEmail) {
// 邮箱 + 密码登录(Supabase Auth
// 1) 调用 Supabase Auth 登录
const result = await supa.signIn(account.value.trim(), password.value)
console.log('signIn result:', result)
// 检查登录是否失败
if (result.user == null) {
// 检查是否是邮箱未确认的错误
const rawData = result.raw as UTSJSONObject
const errorMsg = rawData?.getString('msg') ?? ''
const errorCode = rawData?.getString('error_code') ?? ''
@@ -317,12 +372,25 @@ const handleLogin = async () => {
errorMsg.includes('邮箱') && errorMsg.includes('确认')) {
throw new Error('邮箱未确认,请先检查邮箱并点击确认链接')
} else if (errorMsg.includes('Invalid login credentials') ||
errorCode === 'invalid_credentials') {
errorCode === 'invalid_credentials' ||
errorMsg.includes('Invalid credentials')) {
throw new Error('邮箱或密码错误')
} else {
throw new Error(errorMsg || '登录失败,请重试')
}
}
// 2) 【核心逻辑】:执行商家端角色准入校验
// 优先使用 session user id 来查询数据库里的真实 user 数据兜底校验
const sessionUser = result.user
let sessionUid = sessionUser?.getString('id') ?? ''
const isMerchant = await checkMerchantAccess(sessionUid, account.value)
if (!isMerchant) {
await supa.signOut()
logout()
throw new Error('您还没有注册商家端账户,快去注册一个')
}
} else {
uni.showToast({ title: '手机号密码登录功能开发中', icon: 'none' })
return
@@ -332,27 +400,26 @@ const handleLogin = async () => {
return
}
// 尝试获取/补全用户资料,但失败时不再阻塞登录
// 更新 store 中的用户资料
try {
const profile = await getCurrentUser()
console.log('current user profile:', profile)
console.log('fetch profile success:', profile)
} catch (e) {
console.error('获取用户信息失败(忽略,不阻塞登录:', e)
console.error('获取用户信息失败(忽略):', e)
}
// 显式保存用户ID到本地存储,确保页面刷新或重启后 SupabaseService 能恢复身份
// 显式保存用户ID到本地存储
const currentSession = supa.getSession()
if (currentSession.user != null) {
const uid = currentSession.user?.getString('id')
if (uid != null) {
uni.setStorageSync('user_id', uid)
console.log('用户ID已保存到本地存储:', uid)
}
}
uni.showToast({ title: '登录成功', icon: 'success' })
// 即使在测试模式下,点击登录后也执行跳转,确保进入首页
// 成功跳转逻辑
setTimeout(() => {
const pages = getCurrentPages() as any[]
const currentPage = pages.length > 0 ? pages[pages.length - 1] : null