【修改】 1、强制登出页面优化;2、系统token管理优化

This commit is contained in:
dlaren
2025-08-30 20:28:33 +08:00
parent 1e14e1df2c
commit 1f798663ba
2 changed files with 68 additions and 78 deletions

View File

@@ -21,9 +21,9 @@ const ignoreMsgs = [
export const isRelogin = { show: false }
// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
// 请求队列
let requestList: any[] = []
const requestList: any[] = []
// 是否正在刷新中
let isRefreshToken = false
const isRefreshToken = false
// 请求白名单无须token的接口
const whiteList: string[] = ['/login', '/refresh-token']
@@ -109,45 +109,48 @@ service.interceptors.response.use(
// 如果是忽略的错误码,直接返回 msg 异常
return Promise.reject(msg)
} else if (code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true
// 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!getRefreshToken()) {
return handleAuthorized()
}
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求
setToken((await refreshTokenRes).data.data)
config.headers!.Authorization = 'Bearer ' + getAccessToken()
requestList.forEach((cb: any) => {
cb()
})
requestList = []
return service(config)
} catch (e) {
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求
requestList.forEach((cb: any) => {
cb()
})
// 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized()
} finally {
requestList = []
isRefreshToken = false
}
} else {
// 添加到队列,等待刷新获取到新的令牌
return new Promise((resolve) => {
requestList.push(() => {
config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(service(config))
})
})
}
// 如果未进行认证,返回登录页面(切换浏览器等均会触发)
console.log(msg)
return handleAuthorized()
// // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
// if (!isRefreshToken) {
// isRefreshToken = true
// // 1. 如果获取不到刷新令牌,则只能执行登出操作
// if (!getRefreshToken()) {
// return handleAuthorized()
// }
// // 2. 进行刷新访问令牌
// try {
// const refreshTokenRes = await refreshToken()
// // 2.1 刷新成功,则回放队列的请求 + 当前请求
// setToken((await refreshTokenRes).data.data)
// config.headers!.Authorization = 'Bearer ' + getAccessToken()
// requestList.forEach((cb: any) => {
// cb()
// })
// requestList = []
// return service(config)
// } catch (e) {
// // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// // 2.2 刷新失败,只回放队列的请求
// requestList.forEach((cb: any) => {
// cb()
// })
// // 提示是否要登出。即不回放当前请求!不然会形成递归
// return handleAuthorized()
// } finally {
// requestList = []
// isRefreshToken = false
// }
// } else {
// // 添加到队列,等待刷新获取到新的令牌
// return new Promise((resolve) => {
// requestList.push(() => {
// config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
// resolve(service(config))
// })
// })
// }
} else if (code === 500) {
ElMessage.error(t('sys.api.errMsg500'))
return Promise.reject(new Error(msg))

View File

@@ -81,6 +81,29 @@
/>
</el-form-item>
</el-col>
<el-col v-if="isTrueLoginForAdminPassWord" :span="24" style="padding-right: 10px; padding-left: 10px">
<el-form-item prop="password">
<el-input
v-model="adminPassword"
:placeholder="t('请输入管理员密码')"
:prefix-icon="iconLock"
show-password
type="password"
@keyup.enter="getCode()"
/>
</el-form-item>
</el-col>
<el-col v-if="isTrueLoginForAdminPassWord" :span="24" style="padding-right: 10px; padding-left: 10px">
<el-form-item>
<XButton
:loading="loginLoading"
:title="t('使用管理员密码进行强制退出后,再点击登录按钮')"
class="w-[100%]"
type="primary"
@click="loginOutAdminPassword()"
/>
</el-form-item>
</el-col>
<Verify
v-if="loginData.captchaEnable === 'true'"
ref="verify"
@@ -149,39 +172,6 @@
<!-- </el-col>-->
</el-row>
</el-form>
<el-dialog
v-model="isTrueLoginForAdmin"
title="提示"
width="500"
:before-close="handleClose"
>
<span>是否使用管理员密码强制退出该用户</span>
<template #footer>
<div class="dialog-footer">
<el-button @click="isTrueLoginForAdmin = false">取消</el-button>
<el-button type="primary" @click="openLoginForAdminPassWord()">
确定
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
v-model="isTrueLoginForAdminPassWord"
title="提示"
width="500"
:before-close="handleClose"
>
<span>管理员密码</span>
<el-input v-model="adminPassword" style="width: 240px" placeholder="请输入管理员密码" />
<template #footer>
<div class="dialog-footer">
<el-button @click="isTrueLoginForAdminPassWord = false">取消</el-button>
<el-button type="primary" @click="loginOutAdminPassword()">
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ElLoading } from 'element-plus'
@@ -197,7 +187,6 @@ import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
defineOptions({ name: 'LoginForm' })
const isTrueLoginForAdmin = ref(false)
const isTrueLoginForAdminPassWord = ref(false)
const adminPassword = ref('')
@@ -273,7 +262,6 @@ const getTenantId = async () => {
}
// 使用管理员密码登出登录的账号
const openLoginForAdminPassWord = () => {
isTrueLoginForAdmin.value = false
isTrueLoginForAdminPassWord.value = true
}
const loginOutAdminPassword = async () => {
@@ -284,7 +272,6 @@ const loginOutAdminPassword = async () => {
LoginApi.refreshLogout(data).then((res) => {
if (res) {
message.success(res)
isTrueLoginForAdmin.value = false
isTrueLoginForAdminPassWord.value = false
}
}).catch((err) => {
@@ -353,7 +340,7 @@ const handleLogin = async (params: any) => {
}
} finally {
// 弹出输入管理员密码并重新进行登录
isTrueLoginForAdmin.value = true
isTrueLoginForAdminPassWord.value = true
loginLoading.value = false
loading.value.close()
}