Compare commits

..

3 Commits

Author SHA1 Message Date
437522232c revert 0edceecfe5
revert 修复登录bug
2025-11-17 15:09:32 +00:00
14e47bb35e revert f583f787f0
revert fix: 修复登录后跳转然后返回登录页的问题

- 移除Dashboard组件中重复的token验证调用
- 优化auth store的initAuth方法,增加详细错误处理和日志
- 改进API响应拦截器,减少对/auth/me请求的自动重定向
- 添加路由守卫调试日志,方便定位路由跳转问题
- 解决登录时的竞态条件和重复验证问题

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 15:06:52 +00:00
268ee4d055 revert 21f4ff65d9
revert fix: 修复登录后立即验证token失败的问题

- 修改Dashboard组件,对于已登录用户跳过重复的token验证
- 在LoginForm中添加详细的认证状态日志
- 优化initAuth方法,避免对已登录用户的重复验证
- 添加认证状态检查,确保登录成功后再跳转
- 解决登录成功后立即调用/auth/me导致401的时序问题

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 15:03:18 +00:00
7 changed files with 43 additions and 97 deletions

View File

@@ -257,7 +257,7 @@ export const authController = {
}, },
// 用户登出 // 用户登出
async logout(req: Request, res: Response) { async logout(req: AuthRequest, res: Response) {
const token = req.headers.authorization?.substring(7); const token = req.headers.authorization?.substring(7);
if (token) { if (token) {
@@ -267,27 +267,19 @@ export const authController = {
}); });
} }
// Create audit log (if we have user info from token) // Create audit log
try { if (req.user) {
if (token) {
const decoded = jwt.verify(token, "pandora") as any;
if (decoded && decoded.userId) {
await prisma.auditLog.create({ await prisma.auditLog.create({
data: { data: {
userId: decoded.userId, userId: req.user.id,
action: 'USER_LOGOUT', action: 'USER_LOGOUT',
resource: 'user', resource: 'user',
resourceId: decoded.userId, resourceId: req.user.id,
ipAddress: (req.headers['x-forwarded-for'] as string) || req.socket.remoteAddress || null, ipAddress: (req.headers['x-forwarded-for'] as string) || req.socket.remoteAddress || null,
userAgent: req.get('User-Agent') ?? null, userAgent: req.get('User-Agent') ?? null,
} }
}); });
} }
}
} catch (error) {
// Token无效不记录审计日志
console.log('登出时token无效跳过审计日志记录');
}
res.json({ message: '登出成功' }); res.json({ message: '登出成功' });
}, },

View File

@@ -27,7 +27,7 @@ router.post('/login', [
], authController.login); ], authController.login);
// Logout // Logout
router.post('/logout', authController.logout); router.post('/logout', authMiddleware, authController.logout);
// Get current user // Get current user
router.get('/me', authMiddleware, authController.getCurrentUser); router.get('/me', authMiddleware, authController.getCurrentUser);

View File

@@ -99,18 +99,11 @@ const handleLogin = async () => {
} }
try { try {
const response = await authStore.login({ await authStore.login({
username: loginForm.username, username: loginForm.username,
password: loginForm.password password: loginForm.password
}) })
console.log('登录成功,响应数据:', response)
console.log('Auth store状态:', {
isLoggedIn: authStore.isLoggedIn,
hasToken: !!authStore.token,
hasUser: !!authStore.user
})
// 如果选择记住我,保存登录信息到本地存储 // 如果选择记住我,保存登录信息到本地存储
if (loginForm.rememberMe) { if (loginForm.rememberMe) {
localStorage.setItem('rememberedUser', JSON.stringify({ localStorage.setItem('rememberedUser', JSON.stringify({
@@ -121,14 +114,7 @@ const handleLogin = async () => {
localStorage.removeItem('rememberedUser') localStorage.removeItem('rememberedUser')
} }
// 确保状态已正确设置后再跳转
if (authStore.isLoggedIn) {
console.log('认证状态确认成功即将跳转到Dashboard')
router.push('/dashboard') router.push('/dashboard')
} else {
console.error('登录后认证状态异常')
toast.error('登录状态异常,请重试')
}
} catch (error: any) { } catch (error: any) {
console.error('登录失败,详细错误信息:', { console.error('登录失败,详细错误信息:', {
status: error.response?.status, status: error.response?.status,

View File

@@ -1,4 +1,5 @@
import { createRouter, createWebHistory, type RouteRecordRaw, type NavigationGuardNext, type RouteLocationNormalized } from 'vue-router' import type { RouteRecordRaw, NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import { adminAuth } from '@/utils/auth' import { adminAuth } from '@/utils/auth'
@@ -67,7 +68,7 @@ const router = createRouter({
// 路由守卫 // 路由守卫
router.beforeEach(async ( router.beforeEach(async (
to: RouteLocationNormalized, to: RouteLocationNormalized,
from: RouteLocationNormalized, _from: RouteLocationNormalized,
next: NavigationGuardNext next: NavigationGuardNext
) => { ) => {
// 设置页面标题 // 设置页面标题
@@ -75,13 +76,15 @@ router.beforeEach(async (
document.title = `${title} - AI` document.title = `${title} - AI`
const authStore = useAuthStore() const authStore = useAuthStore()
// 用户已登录重定向到dashboard
console.log(`路由守卫: ${from.path} -> ${to.path}, 用户登录状态: ${authStore.isLoggedIn}`) if (to.path === '/' && authStore.isLoggedIn) {
next({ name: 'Dashboard' })
return
}
// 检查是否需要用户认证 // 检查是否需要用户认证
if (to.meta.requiresAuth) { if (to.meta.requiresAuth) {
if (!authStore.isLoggedIn) { if (!authStore.isLoggedIn) {
console.log('需要登录,重定向到首页')
next('/') next('/')
return return
} }
@@ -90,19 +93,11 @@ router.beforeEach(async (
// 检查是否需要管理员认证 // 检查是否需要管理员认证
if (to.meta.requiresAdminAuth) { if (to.meta.requiresAdminAuth) {
if (!adminAuth.isLoggedIn()) { if (!adminAuth.isLoggedIn()) {
console.log('需要管理员登录,重定向到管理员登录页')
next('/admin/login') next('/admin/login')
return return
} }
} }
// 用户已登录且访问首页重定向到dashboard
if (to.path === '/' && authStore.isLoggedIn) {
console.log('用户已登录重定向到dashboard')
next({ name: 'Dashboard' })
return
}
next() next()
}) })

View File

@@ -16,31 +16,18 @@ export const useAuthStore = defineStore('auth', () => {
// 初始化认证状态 // 初始化认证状态
const initAuth = async () => { const initAuth = async () => {
// 如果已经登录,不需要重新初始化
if (isLoggedIn.value) {
console.log('用户已登录,跳过初始化')
return
}
const storedToken = userAuth.getToken() const storedToken = userAuth.getToken()
const storedUser = userAuth.getUserInfo() const storedUser = userAuth.getUserInfo()
if (storedToken && storedUser) { if (storedToken && storedUser) {
console.log('从本地存储恢复登录状态')
token.value = storedToken token.value = storedToken
user.value = storedUser user.value = storedUser
try { try {
// 验证token有效性
await getProfile() await getProfile()
console.log('Token验证成功用户已登录') } catch (error) {
} catch (error: any) {
console.log('Token验证失败清除本地存储:', error.response?.status)
// token失效清除本地存储 // token失效清除本地存储
await logout() logout()
throw error // 重新抛出错误,让调用方知道初始化失败
} }
} else {
console.log('本地存储中无有效的登录信息')
} }
} }

View File

@@ -41,25 +41,12 @@ api.interceptors.response.use(
}, },
(error) => { (error) => {
if (error.response?.status === 401) { if (error.response?.status === 401) {
// 如果是登出请求或获取用户信息的请求,不要自动重定向,让上层处理
if (error.config?.url?.includes('/auth/logout') ||
error.config?.url?.includes('/auth/me')) {
return Promise.reject(error)
}
console.log('收到401响应URL:', error.config?.url)
// Token过期或无效清除所有认证状态 // Token过期或无效清除所有认证状态
userAuth.logout() userAuth.logout()
adminAuth.logout() adminAuth.logout()
// 只有在非登录相关页面时才自动重定向 // 自动重定向到登录页面(如果不是已经在登录页面)
const currentPath = window.location.pathname if (window.location.pathname !== '/' && window.location.pathname !== '/login') {
if (currentPath !== '/' &&
currentPath !== '/login' &&
currentPath !== '/admin/login' &&
!currentPath.includes('/auth')) {
console.log('自动重定向到首页')
window.location.href = '/' window.location.href = '/'
} }
} }

View File

@@ -201,22 +201,8 @@ const loadUserAccounts = async () => {
// 组件挂载时获取数据 // 组件挂载时获取数据
onMounted(async () => { onMounted(async () => {
try { try {
console.log('Dashboard初始化开始当前认证状态:', { // 初始化认证状态
isLoggedIn: authStore.isLoggedIn, authStore.initAuth()
hasToken: !!authStore.token,
hasUser: !!authStore.user,
hasLocalToken: !!localStorage.getItem('userToken'),
hasLocalUser: !!localStorage.getItem('userInfo')
})
// 如果用户已经登录(比如刚从登录页面跳转过来),直接使用当前状态
if (authStore.isLoggedIn) {
console.log('用户已登录,直接加载账号数据')
} else {
// 否则尝试从localStorage恢复状态
console.log('用户未登录,尝试初始化认证状态')
await authStore.initAuth()
}
// 确保用户已登录 // 确保用户已登录
if (!authStore.isLoggedIn) { if (!authStore.isLoggedIn) {
@@ -225,6 +211,19 @@ onMounted(async () => {
return return
} }
// 验证token是否有效通过尝试获取用户信息
try {
await authStore.getProfile()
} catch (error: any) {
if (error.response?.status === 401) {
// Token无效清除认证状态并重定向
authStore.logout()
toast.error('登录已过期,请重新登录')
router.push('/')
return
}
}
// 加载用户账号 // 加载用户账号
await loadUserAccounts() await loadUserAccounts()
} catch (error: any) { } catch (error: any) {