/** * 路由守卫 * 提供APP连接检查、页面访问权限控制和自动重定向功能 */ import { permissionManager, PAGES, USER_ROLES } from './permissionManager.js' import { getUserIdentity, getMemberProfile } from '../api/wallet.js' import { getUserId, setUserInfo } from './userStore.js' import { connectApplication, parseAccessOrigin, parseHeader, setHttpHeaders, isInApp, } from './appBridge.js' import { appConnectionManager, isAppConnected } from './appConnectionManager.js' /** * APP连接检查器 */ class AppConnectionChecker { constructor() { this.isConnecting = false } /** * 确保APP连接 * @returns {Promise} 连接是否成功 */ async ensureConnection() { console.debug('🔗 Checking APP connection...') // 如果不在APP环境中,直接返回成功 console.log('我是app环境', window.app) console.log('我是app环境', window.webkit) console.log('我是app环境', window.FlutterPageControl) if (!isInApp()) { console.debug('🌐 Browser environment, no connection needed') return true } // 如果已经连接且未超时,直接返回成功 if (isAppConnected()) { console.debug('✅ APP already connected') return true } // 如果正在连接中,等待现有连接 if (appConnectionManager.isConnecting()) { console.debug('⏳ Connection already in progress, waiting...') try { await appConnectionManager.getConnectionPromise() return isAppConnected() } catch (error) { console.error('❌ Connection wait failed:', error) return false } } // 开始新的连接 return await this._performConnection() } /** * 执行APP连接 * @returns {Promise} */ async _performConnection() { try { console.debug('📱 Starting new APP connection...') const connectionPromise = new Promise((resolve, reject) => { connectApplication(async (access) => { try { const result = parseAccessOrigin(access) if (result.success) { // 解析头部信息 const headerInfo = parseHeader(result.data) // 设置HTTP请求头 await setHttpHeaders(headerInfo) // 更新连接状态 appConnectionManager.setConnected(headerInfo) console.debug('🎉 APP connection established successfully') // APP连接成功后立即获取用户信息 await this._fetchUserInfoAfterConnection() resolve(true) } else { console.error('❌ Failed to parse access origin:', result.error) appConnectionManager.reset() reject(new Error(result.error)) } } catch (error) { console.error('❌ Connection process failed:', error) appConnectionManager.reset() reject(error) } }) }) // 设置连接状态 appConnectionManager.setConnecting(connectionPromise) // 等待连接完成 return await connectionPromise } catch (error) { console.error('❌ APP connection failed:', error) appConnectionManager.reset() return false } } /** * APP连接成功后获取用户信息 * @private */ async _fetchUserInfoAfterConnection() { try { console.debug('👤 Fetching user info after connection...') const response = await getMemberProfile() if (response && response.status && response.body) { // 缓存用户信息 console.debug('✅ User info cached successfully') setUserInfo(response.body, null) } else { console.warn('⚠️ Failed to get team entry or invalid response') } } catch (error) { // 这里不抛出错误,因为APP连接已经成功 // 用户信息获取失败可以在后续的身份检查中处理 console.warn('⚠️ Failed to fetch user info after connection:', error) } } /** * 重置连接状态 */ reset() { appConnectionManager.reset() } } /** * 身份检查器 */ class IdentityChecker { constructor() { this.isChecking = false this.checkPromise = null } /** * 检查并设置用户身份 * @param {string} userId - 用户ID * @returns {Promise} 返回主要身份 */ async checkUserIdentity(userId) { if (!userId) { console.warn('⚠️ No user ID provided') permissionManager.setUserIdentity(null) return USER_ROLES.GUEST } // 如果正在检查中,等待现有的检查完成 if (this.isChecking && this.checkPromise) { console.debug('⏳ Identity check already in progress, waiting...') return await this.checkPromise } this.isChecking = true this.checkPromise = this._performIdentityCheck(userId) try { const primaryRole = await this.checkPromise return primaryRole } finally { this.isChecking = false this.checkPromise = null } } /** * 执行实际的身份检查 * @param {string} userId - 用户ID * @returns {Promise} 主要身份 */ async _performIdentityCheck(userId) { try { console.debug('🔍 Checking user identity for:', userId) const response = await getUserIdentity() if (response && response.status && response.body) { const identity = response.body console.debug('✅ Identity fetched:', identity) // 设置权限信息 permissionManager.setUserIdentity(identity) return permissionManager.getPrimaryRole() } else { console.warn('⚠️ Invalid identity response') permissionManager.setUserIdentity(null) return USER_ROLES.GUEST } } catch (error) { console.error('❌ Failed to fetch user identity:', error) permissionManager.setUserIdentity(null) return USER_ROLES.GUEST } } /** * 重置检查状态 */ reset() { this.isChecking = false this.checkPromise = null } } /** * 页面重定向器 */ class PageRedirector { /** * 根据身份自动重定向到正确页面 * @param {Object} router - Vue Router 实例 * @param {string} targetPath - 目标页面路径 * @param {string} currentPath - 当前页面路径 * @returns {Promise} 是否进行了重定向 */ async redirectToCorrectPage(router, targetPath, currentPath) { const primaryRole = permissionManager.getPrimaryRole() // 检查目标页面权限 const hasPermission = permissionManager.hasPagePermission(targetPath) console.debug('🔄 Redirect check:', { targetPath, currentPath, primaryRole, hasPermission, }) if (hasPermission) { // 有权限访问目标页面 if (targetPath !== currentPath) { console.debug('✅ Access granted, navigating to:', targetPath) return false // 不需要重定向,让路由正常进行 } return false } else { // 无权限访问,重定向到默认页面 const defaultPage = permissionManager.getDefaultPage() console.debug('❌ Access denied, redirecting to:', defaultPage) if (defaultPage !== currentPath) { await router.replace(defaultPage) return true // 已进行重定向 } return false } } /** * 处理越权访问 * @param {Object} router - Vue Router 实例 * @param {string} attemptedPage - 尝试访问的页面 */ async handleUnauthorizedAccess(router, attemptedPage) { const primaryRole = permissionManager.getPrimaryRole() const defaultPage = permissionManager.getDefaultPage() console.warn('🚫 Unauthorized access attempt:', { attemptedPage, primaryRole, redirectingTo: defaultPage, }) // 重定向到用户有权限的默认页面 await router.replace(defaultPage) } } /** * 路由守卫类 */ class RouteGuard { constructor() { this.appConnectionChecker = new AppConnectionChecker() this.identityChecker = new IdentityChecker() this.pageRedirector = new PageRedirector() this.isGuardActive = false } /** * 安装路由守卫 * @param {Object} router - Vue Router 实例 */ install(router) { router.beforeEach(async (to, from, next) => { await this.handleRouteChange(to, from, next) }) this.isGuardActive = true console.debug('🛡️ Route guard installed') } /** * 处理路由变化 * @param {Object} to - 目标路由 * @param {Object} from - 来源路由 * @param {Function} next - 路由继续函数 */ async handleRouteChange(to, from, next) { console.group('🛡️ Route Guard Check') console.debug('📍 Route change:', from.path, '→', to.path) try { // 1. 检查是否为公共页面(无需任何验证) if (this.isPublicPage(to.path)) { console.debug('🌐 Public page, allowing access') console.groupEnd() next() return } // 2. 确保APP连接 console.debug('🔗 Ensuring APP connection...') const isConnected = await this.appConnectionChecker.ensureConnection() if (!isConnected) { console.error('❌ APP connection failed, redirecting to error page') console.groupEnd() next(PAGES.NOT_APP) return } // 3. 检查用户身份是否已加载 if (!permissionManager.isLoaded()) { console.debug('🔍 Identity not loaded, checking...') const userId = getUserId() if (!userId) { console.debug('❌ No user ID available, redirecting to apply') console.groupEnd() next(PAGES.APPLY) return } // 检查用户身份 await this.identityChecker.checkUserIdentity(userId) } // 4. 检查页面访问权限 const hasPermission = permissionManager.hasPagePermission(to.path) if (hasPermission) { console.debug('✅ Permission granted, allowing access') console.groupEnd() next() } else { console.debug('❌ Permission denied') const defaultPage = permissionManager.getDefaultPage() console.debug('🔄 Redirecting to default page:', defaultPage) console.groupEnd() next(defaultPage) } } catch (error) { console.error('❌ Route guard error:', error) console.groupEnd() // 根据错误类型决定重定向目标 if (error.message && error.message.includes('connection')) { next(PAGES.NOT_APP) // 连接相关错误 } else { next(PAGES.APPLY) // 其他错误 } } } /** * 检查是否为公共页面(无需APP连接和权限验证) * @param {string} path - 页面路径 * @returns {boolean} */ isPublicPage(path) { //排行榜 const RANKING_PAGES = [ '/top-list', //排行榜 '/weekly-star', //每周明星 '/ranking', //总排行榜 '/games-king', //游戏排行榜 '/couple', //情侣排行榜 ] // 活动页面 const ACTIVITIES = [ '/invitation-to-register', //邀请新用户注册页面 '/invite-new-user', //邀请新用户 '/recharge-reward', //充值奖励 '/login-reward', // 登录奖励 '/activities/lucky-dollars-season3', // 斋月打榜 '/activities/spring-festival', // 春节打榜 ] const publicPages = [ PAGES.APPLY, // 申请页面 - 重要:申请页面不需要权限检查 PAGES.NOT_APP, // 错误页面 - APP连接失败时的页面 PAGES.MAP, // 地图选择页面 ...RANKING_PAGES, //排行榜 ...ACTIVITIES, // 活动页面 '/404', // 404页面 '/error', // 通用错误页面 '/recharge', //搜索充值对象页面 '/recharge-pay-way', //充值方式页面 '/recharge-guide', //充值引导页面 '/recharge-agency-recruit', //充值代理介绍页面 '/pay-result', //支付结果页 '/search-payee', //搜索收款人 '/cash-out', // 提现页面 '/cash-out-details', //提现详情页面 '/KYC', //提现资料提交 '/bank-card', //选择银行卡 '/good-ID', //靓号申请页 ] return publicPages.includes(path) } /** * 手动触发身份检查和重定向 * @param {Object} router - Vue Router 实例 * @param {string} userId - 用户ID */ async checkAndRedirect(router, userId) { try { console.debug('🔄 Manual identity check and redirect') // 检查身份 const primaryRole = await this.identityChecker.checkUserIdentity(userId) // 获取当前页面 const currentPath = router.currentRoute.value.path // 检查当前页面权限 const hasPermission = permissionManager.hasPagePermission(currentPath) if (!hasPermission) { // 重定向到默认页面 await this.pageRedirector.redirectToCorrectPage(router, currentPath, currentPath) } return primaryRole } catch (error) { console.error('❌ Manual check and redirect failed:', error) throw error } } /** * 重置守卫状态 */ reset() { this.appConnectionChecker.reset() this.identityChecker.reset() permissionManager.reset() console.debug('🔄 Route guard reset') } } // 创建全局路由守卫实例 export const routeGuard = new RouteGuard() // 便捷方法 export const installRouteGuard = (router) => routeGuard.install(router) export const checkAndRedirect = (router, userId) => routeGuard.checkAndRedirect(router, userId) export const resetRouteGuard = () => routeGuard.reset()