diff --git a/frontend/src/components/navbar/Navbar.vue b/frontend/src/components/navbar/Navbar.vue index 70a8973b1..e72fba651 100644 --- a/frontend/src/components/navbar/Navbar.vue +++ b/frontend/src/components/navbar/Navbar.vue @@ -965,7 +965,7 @@ this.selectedItems = [] this.selectAll = false } else { - ElMessage.warning(error.value.msg) + ElMessage.warning(error.value?.msg) } }, async allClear() { @@ -992,7 +992,7 @@ this.selectedItems = [] this.selectAll = false } else { - ElMessage.warning(error.value.msg) + ElMessage.warning(error.value?.msg) } }, handleLocaleChange(locale) { @@ -1005,7 +1005,6 @@ if (data.value) { this.userStore.initialize(data.value.data) } else { - console.log(error.value.msg) this.clearCookies() } }, @@ -1077,7 +1076,7 @@ if (data.value) { ElMessage.success(this.$t('navbar.settingsSuccess')) } else { - ElMessage.warning(error.value.msg) + ElMessage.warning(error.value?.msg) } }, async subForm() { @@ -1105,7 +1104,7 @@ ElMessage.success(this.$t('navbar.settingsSuccess')) this.showUserSet = false } else { - ElMessage.warning(error.value.msg) + ElMessage.warning(error.value?.msg) } } catch (error) { console.log('表单验证失败:', error) @@ -1127,7 +1126,7 @@ this.msgList[index].is_read = true this.getMsgNum() } else { - ElMessage.warning(error.value.msg) + ElMessage.warning(error.value?.msg) } }, async getMsgNum() { diff --git a/frontend/src/packs/authDialog.js b/frontend/src/packs/authDialog.js new file mode 100644 index 000000000..1a5d57e9a --- /dev/null +++ b/frontend/src/packs/authDialog.js @@ -0,0 +1,39 @@ +import { useCookies } from 'vue3-cookies' +import { ElMessageBox } from 'element-plus' +import { user_sessions as sessions_en } from '../locales/en_js/user_sessions.js' +import { user_sessions as sessions_zh } from '../locales/zh_js/user_sessions.js' +import { logout } from './auth' +import { dialogState } from './dialogState' + +const { cookies } = useCookies() + +export const popupReloginDialog = () => { + if (dialogState.isReloginDialogShowing) { + return + } + + dialogState.isReloginDialogShowing = true + + const currentURL = window.location.pathname + window.location.search + window.location.hash; + cookies.set('previous_path', currentURL, '7d', '/', '', false, false); + + const sessionLocale = cookies.get('locale') === 'en' ? sessions_en : sessions_zh + + ElMessageBox.confirm(sessionLocale.expiredDesc, sessionLocale.expiredTitle, { + showClose: true, + closeOnClickModal: true, + closeOnPressEscape: true, + confirmButtonText: sessionLocale.reLogin, + cancelButtonText: sessionLocale.cancel + }).then(() => { + const previousPath = cookies.get('previous_path') + logout() + cookies.set('previous_path', previousPath, '7d', '/', '', false, false) + window.location.href = '/login' + }).catch(() => { + logout() + window.location.href = '/logout' + }).finally(() => { + dialogState.isReloginDialogShowing = false + }) +} diff --git a/frontend/src/packs/dialogState.js b/frontend/src/packs/dialogState.js new file mode 100644 index 000000000..82e67cc89 --- /dev/null +++ b/frontend/src/packs/dialogState.js @@ -0,0 +1,4 @@ +// 全局共享的对话框状态,防止重复弹出登录对话框 +export const dialogState = { + isReloginDialogShowing: false +} diff --git a/frontend/src/packs/jwtFetch.js b/frontend/src/packs/jwtFetch.js index 6ca67b6c6..310b011ae 100644 --- a/frontend/src/packs/jwtFetch.js +++ b/frontend/src/packs/jwtFetch.js @@ -4,6 +4,8 @@ const { cookies } = useCookies(); const jwtFetch = (url, options = {}, forceLogin = false) => { const jwtToken = cookies.get('user_token') if (forceLogin && !jwtToken) { + const fullPath = window.location.pathname + window.location.search + window.location.hash; + cookies.set('previous_path', fullPath, '7d', '/', '', false, false); window.location.href = "/login" } options.headers = options.headers || {} diff --git a/frontend/src/packs/refreshJWT.js b/frontend/src/packs/refreshJWT.js index 1519f8ecc..e780d2402 100644 --- a/frontend/src/packs/refreshJWT.js +++ b/frontend/src/packs/refreshJWT.js @@ -1,5 +1,6 @@ import { useCookies } from "vue3-cookies"; import { jwtDecode } from "jwt-decode"; +import { popupReloginDialog } from './authDialog' const { cookies } = useCookies() @@ -10,20 +11,35 @@ const refreshJWT = async () => { if(loginIdentity) { if (jwt) { - const jwtInfos = jwtDecode(jwt); - const expireTime = jwtInfos.exp; - if (currentTime >= expireTime) { - await fetch('/internal_api/users/jwt_token', {method: 'PUT'}) - } else { - // if user token will expire soon, refresh - // if user token will not expire soon, do nothing - const differenceInMinutes = Math.floor((expireTime - currentTime) / (60)); - if (differenceInMinutes < 120) { - await fetch('/internal_api/users/jwt_token', {method: 'PUT'}) + try { + const jwtInfos = jwtDecode(jwt); + const expireTime = jwtInfos.exp; + if (currentTime >= expireTime) { + const response = await fetch('/internal_api/users/jwt_token', {method: 'PUT'}) + if (!response.ok) { + throw new Error('Token refresh failed') + } + } else { + const differenceInMinutes = Math.floor((expireTime - currentTime) / (60)); + if (differenceInMinutes < 120) { + const response = await fetch('/internal_api/users/jwt_token', {method: 'PUT'}) + if (!response.ok) { + throw new Error('Token refresh failed') + } + } } + } catch (error) { + popupReloginDialog() } } else { - await fetch('/internal_api/users/jwt_token', {method: 'PUT'}) + try { + const response = await fetch('/internal_api/users/jwt_token', {method: 'PUT'}) + if (!response.ok) { + throw new Error('Token refresh failed') + } + } catch (error) { + popupReloginDialog() + } } } } diff --git a/frontend/src/packs/useFetchApi.js b/frontend/src/packs/useFetchApi.js index 6bfb6d0e2..3dc7d4e55 100644 --- a/frontend/src/packs/useFetchApi.js +++ b/frontend/src/packs/useFetchApi.js @@ -7,10 +7,21 @@ import { user_sessions as sessions_en } from '../locales/en_js/user_sessions.js' import { user_sessions as sessions_zh } from '../locales/zh_js/user_sessions.js' import { logout } from './auth' +import { getDefaultLanguage } from './utils' +import { dialogState } from './dialogState' const { cookies } = useCookies() const popupReloginDialog = () => { + if (dialogState.isReloginDialogShowing) { + return + } + + dialogState.isReloginDialogShowing = true + + const currentURL = window.location.pathname + window.location.search; + cookies.set('previous_path', currentURL, '7d', '/', '', false, false); + const sessionLocale = cookies.get('locale') === 'en' ? sessions_en : sessions_zh ElMessageBox.confirm(sessionLocale.expiredDesc, sessionLocale.expiredTitle, { @@ -19,13 +30,17 @@ const popupReloginDialog = () => { 'cancelButtonText': sessionLocale.cancelLogin }) .then(() => { - window.location.href = '/logout?redirect_to=/login' + const previousPath = cookies.get('previous_path') + logout() + cookies.set('previous_path', previousPath, '7d', '/', '', false, false) + window.location.href = '/login' }) .catch(() => { + logout() window.location.href = '/logout' }) .finally(() => { - logout() + dialogState.isReloginDialogShowing = false }) } diff --git a/frontend/src/packs/utils.js b/frontend/src/packs/utils.js index 5d2e211e2..869532323 100644 --- a/frontend/src/packs/utils.js +++ b/frontend/src/packs/utils.js @@ -62,7 +62,8 @@ export const beiJingTimeParser = (utcTimeStr) => { } export const ToLoginPage = () => { - cookies.set('previous_path', window.location.pathname) + const currentURL = window.location.pathname + window.location.search + window.location.hash; + cookies.set('previous_path', currentURL, '7d', '/', '', false, false); window.location.href = '/login' } diff --git a/internal/handlers/render/session.go b/internal/handlers/render/session.go index 92d455554..41289081f 100644 --- a/internal/handlers/render/session.go +++ b/internal/handlers/render/session.go @@ -144,6 +144,7 @@ func (i *SessionHandlerImpl) Create(ctx *gin.Context) { previousPath, _ := ctx.Cookie("previous_path") if previousPath != "" { + ctx.SetCookie("previous_path", "", -1, "/", "", false, false) ctx.Redirect(http.StatusFound, previousPath) } else { ctx.Redirect(http.StatusFound, "/") diff --git a/internal/middleware/auth_middleware.go b/internal/middleware/auth_middleware.go index 718dfc8f9..4d1e01934 100644 --- a/internal/middleware/auth_middleware.go +++ b/internal/middleware/auth_middleware.go @@ -56,8 +56,11 @@ func (a *MiddlewareImpl) CheckCurrentUser() gin.HandlerFunc { return func(ctx *gin.Context) { currentUser := a.jwtUtils.GetCurrentUser(ctx) if currentUser == nil { - currentPath := ctx.Request.URL.Path - ctx.SetCookie("previous_path", currentPath, 3600*24*7, "/", "", false, false) + fullURL := ctx.Request.URL.Path + if ctx.Request.URL.RawQuery != "" { + fullURL = fullURL + "?" + ctx.Request.URL.RawQuery + } + ctx.SetCookie("previous_path", fullURL, 3600*24*7, "/", "", false, false) ctx.Redirect(http.StatusFound, "/login") ctx.Abort() return