Compare commits
3 Commits
21f4ff65d9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 437522232c | |||
| 14e47bb35e | |||
| 268ee4d055 |
@@ -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);
|
||||
|
||||
if (token) {
|
||||
@@ -267,26 +267,18 @@ export const authController = {
|
||||
});
|
||||
}
|
||||
|
||||
// Create audit log (if we have user info from token)
|
||||
try {
|
||||
if (token) {
|
||||
const decoded = jwt.verify(token, "pandora") as any;
|
||||
if (decoded && decoded.userId) {
|
||||
await prisma.auditLog.create({
|
||||
data: {
|
||||
userId: decoded.userId,
|
||||
action: 'USER_LOGOUT',
|
||||
resource: 'user',
|
||||
resourceId: decoded.userId,
|
||||
ipAddress: (req.headers['x-forwarded-for'] as string) || req.socket.remoteAddress || null,
|
||||
userAgent: req.get('User-Agent') ?? null,
|
||||
}
|
||||
});
|
||||
// Create audit log
|
||||
if (req.user) {
|
||||
await prisma.auditLog.create({
|
||||
data: {
|
||||
userId: req.user.id,
|
||||
action: 'USER_LOGOUT',
|
||||
resource: 'user',
|
||||
resourceId: req.user.id,
|
||||
ipAddress: (req.headers['x-forwarded-for'] as string) || req.socket.remoteAddress || null,
|
||||
userAgent: req.get('User-Agent') ?? null,
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Token无效,不记录审计日志
|
||||
console.log('登出时token无效,跳过审计日志记录');
|
||||
});
|
||||
}
|
||||
|
||||
res.json({ message: '登出成功' });
|
||||
|
||||
@@ -27,7 +27,7 @@ router.post('/login', [
|
||||
], authController.login);
|
||||
|
||||
// Logout
|
||||
router.post('/logout', authController.logout);
|
||||
router.post('/logout', authMiddleware, authController.logout);
|
||||
|
||||
// Get current user
|
||||
router.get('/me', authMiddleware, authController.getCurrentUser);
|
||||
|
||||
@@ -99,18 +99,11 @@ const handleLogin = async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await authStore.login({
|
||||
await authStore.login({
|
||||
username: loginForm.username,
|
||||
password: loginForm.password
|
||||
})
|
||||
|
||||
console.log('登录成功,响应数据:', response)
|
||||
console.log('Auth store状态:', {
|
||||
isLoggedIn: authStore.isLoggedIn,
|
||||
hasToken: !!authStore.token,
|
||||
hasUser: !!authStore.user
|
||||
})
|
||||
|
||||
// 如果选择记住我,保存登录信息到本地存储
|
||||
if (loginForm.rememberMe) {
|
||||
localStorage.setItem('rememberedUser', JSON.stringify({
|
||||
@@ -121,14 +114,7 @@ const handleLogin = async () => {
|
||||
localStorage.removeItem('rememberedUser')
|
||||
}
|
||||
|
||||
// 确保状态已正确设置后再跳转
|
||||
if (authStore.isLoggedIn) {
|
||||
console.log('认证状态确认成功,即将跳转到Dashboard')
|
||||
router.push('/dashboard')
|
||||
} else {
|
||||
console.error('登录后认证状态异常')
|
||||
toast.error('登录状态异常,请重试')
|
||||
}
|
||||
router.push('/dashboard')
|
||||
} catch (error: any) {
|
||||
console.error('登录失败,详细错误信息:', {
|
||||
status: error.response?.status,
|
||||
|
||||
@@ -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 { adminAuth } from '@/utils/auth'
|
||||
|
||||
@@ -67,7 +68,7 @@ const router = createRouter({
|
||||
// 路由守卫
|
||||
router.beforeEach(async (
|
||||
to: RouteLocationNormalized,
|
||||
from: RouteLocationNormalized,
|
||||
_from: RouteLocationNormalized,
|
||||
next: NavigationGuardNext
|
||||
) => {
|
||||
// 设置页面标题
|
||||
@@ -75,13 +76,15 @@ router.beforeEach(async (
|
||||
document.title = `${title} - AI`
|
||||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
console.log(`路由守卫: ${from.path} -> ${to.path}, 用户登录状态: ${authStore.isLoggedIn}`)
|
||||
// 用户已登录,重定向到dashboard
|
||||
if (to.path === '/' && authStore.isLoggedIn) {
|
||||
next({ name: 'Dashboard' })
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否需要用户认证
|
||||
if (to.meta.requiresAuth) {
|
||||
if (!authStore.isLoggedIn) {
|
||||
console.log('需要登录,重定向到首页')
|
||||
next('/')
|
||||
return
|
||||
}
|
||||
@@ -90,19 +93,11 @@ router.beforeEach(async (
|
||||
// 检查是否需要管理员认证
|
||||
if (to.meta.requiresAdminAuth) {
|
||||
if (!adminAuth.isLoggedIn()) {
|
||||
console.log('需要管理员登录,重定向到管理员登录页')
|
||||
next('/admin/login')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 用户已登录且访问首页,重定向到dashboard
|
||||
if (to.path === '/' && authStore.isLoggedIn) {
|
||||
console.log('用户已登录,重定向到dashboard')
|
||||
next({ name: 'Dashboard' })
|
||||
return
|
||||
}
|
||||
|
||||
next()
|
||||
})
|
||||
|
||||
|
||||
@@ -16,31 +16,18 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
|
||||
// 初始化认证状态
|
||||
const initAuth = async () => {
|
||||
// 如果已经登录,不需要重新初始化
|
||||
if (isLoggedIn.value) {
|
||||
console.log('用户已登录,跳过初始化')
|
||||
return
|
||||
}
|
||||
|
||||
const storedToken = userAuth.getToken()
|
||||
const storedUser = userAuth.getUserInfo()
|
||||
|
||||
if (storedToken && storedUser) {
|
||||
console.log('从本地存储恢复登录状态')
|
||||
token.value = storedToken
|
||||
user.value = storedUser
|
||||
try {
|
||||
// 验证token有效性
|
||||
await getProfile()
|
||||
console.log('Token验证成功,用户已登录')
|
||||
} catch (error: any) {
|
||||
console.log('Token验证失败,清除本地存储:', error.response?.status)
|
||||
} catch (error) {
|
||||
// token失效,清除本地存储
|
||||
await logout()
|
||||
throw error // 重新抛出错误,让调用方知道初始化失败
|
||||
logout()
|
||||
}
|
||||
} else {
|
||||
console.log('本地存储中无有效的登录信息')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,25 +41,12 @@ api.interceptors.response.use(
|
||||
},
|
||||
(error) => {
|
||||
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过期或无效,清除所有认证状态
|
||||
userAuth.logout()
|
||||
adminAuth.logout()
|
||||
|
||||
// 只有在非登录相关页面时才自动重定向
|
||||
const currentPath = window.location.pathname
|
||||
if (currentPath !== '/' &&
|
||||
currentPath !== '/login' &&
|
||||
currentPath !== '/admin/login' &&
|
||||
!currentPath.includes('/auth')) {
|
||||
console.log('自动重定向到首页')
|
||||
// 自动重定向到登录页面(如果不是已经在登录页面)
|
||||
if (window.location.pathname !== '/' && window.location.pathname !== '/login') {
|
||||
window.location.href = '/'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,22 +201,8 @@ const loadUserAccounts = async () => {
|
||||
// 组件挂载时获取数据
|
||||
onMounted(async () => {
|
||||
try {
|
||||
console.log('Dashboard初始化开始,当前认证状态:', {
|
||||
isLoggedIn: authStore.isLoggedIn,
|
||||
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()
|
||||
}
|
||||
// 初始化认证状态
|
||||
authStore.initAuth()
|
||||
|
||||
// 确保用户已登录
|
||||
if (!authStore.isLoggedIn) {
|
||||
@@ -225,6 +211,19 @@ onMounted(async () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 验证token是否有效(通过尝试获取用户信息)
|
||||
try {
|
||||
await authStore.getProfile()
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 401) {
|
||||
// Token无效,清除认证状态并重定向
|
||||
authStore.logout()
|
||||
toast.error('登录已过期,请重新登录')
|
||||
router.push('/')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 加载用户账号
|
||||
await loadUserAccounts()
|
||||
} catch (error: any) {
|
||||
|
||||
Reference in New Issue
Block a user