A组认证加固: P0兜底+Token刷新+环境检测+OTP+RBRAC落地+P1日志审计+Token撤销 - 全局一致性审查通过

This commit is contained in:
Simon
2026-07-02 19:06:12 +08:00
parent 78f60c6857
commit fc22de7f4d
12 changed files with 1813 additions and 106 deletions
+18
View File
@@ -41,6 +41,24 @@ const routes = [
title: '正在加载...',
},
},
{
// 错误提示页面(OAuth2 回调异常兜底)
path: '/error',
name: 'ErrorPage',
component: () => import('@/views/ErrorPage.vue'),
meta: {
title: '登录失败',
},
},
{
// 错误提示页面(/login/error 别名,兼容后端重定向)
path: '/login/error',
name: 'LoginError',
component: () => import('@/views/ErrorPage.vue'),
meta: {
title: '登录失败',
},
},
{
// 404 页面
path: '/:pathMatch(.*)*',
+156
View File
@@ -0,0 +1,156 @@
<template>
<!-- OAuth2 登录失败错误页面 -->
<div class="portal-error">
<div class="error-content">
<!-- 错误图标 -->
<div class="error-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" d="M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75.75 0 000 1.5z" clip-rule="evenodd" />
</svg>
</div>
<!-- 登录失败标题 -->
<h2 class="error-title">登录失败</h2>
<!-- 错误信息 -->
<p class="error-message">{{ errorMessage }}</p>
<!-- 重新登录按钮 -->
<button class="back-button" @click="retryLogin">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
<path fill-rule="evenodd" d="M4.5 9.75a6 6 0 0111.573-2.226 3.75 3.75 0 014.133 4.303A4.5 4.5 0 0118 20.25H6.75a5.25 5.25 0 01-2.23-10.004 6.072 6.072 0 01-.02-.496z" clip-rule="evenodd" />
</svg>
重新登录
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
// 从路由 query 获取错误码和错误信息
const errorCode = computed(() => {
const code = route.query.code as string
return code || 'Error'
})
// 错误信息:优先使用 message 参数,否则根据错误码生成友好提示
const errorMessage = computed(() => {
const message = route.query.message as string
if (message) {
return message
}
// 根据错误码生成友好提示
const code = errorCode.value
const errorMessages: Record<string, string> = {
'oauth_failed': '登录过程出现异常,请重试',
'missing_params': '授权参数不完整,请重试',
'state_expired': '授权已过期,请重新进入',
'api_failed': '企业微信服务异常,请重试',
'empty_userid': '无法获取您的企业微信身份,请重试',
'wecom_48001': '应用权限不足,请联系管理员',
'wecom_50001': '授权已失效,请重新进入',
}
return errorMessages[code] || '认证过程中出现错误,请重试'
})
// 重新登录:跳转回首页重新发起 OAuth2 流程
const retryLogin = () => {
router.push('/')
}
onMounted(() => {
// 如果没有错误信息,重定向回入口
if (!route.query.code && !route.query.message) {
router.replace('/')
}
})
</script>
<style scoped>
/* 页面容器 */
.portal-error {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
}
/* 错误内容 */
.error-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 48px;
text-align: center;
}
/* 错误图标 - 企微绿色 */
.error-icon {
width: 80px;
height: 80px;
color: #10b981;
opacity: 0.9;
}
.error-icon svg {
width: 100%;
height: 100%;
}
/* 登录失败标题 */
.error-title {
font-size: 28px;
font-weight: 700;
color: #f1f5f9;
margin: 0;
}
/* 错误信息 */
.error-message {
font-size: 16px;
color: #94a3b8;
margin: 0;
max-width: 360px;
line-height: 1.6;
}
/* 重新登录按钮 - 企微绿色主题 */
.back-button {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
margin-top: 16px;
font-size: 15px;
font-weight: 500;
color: #fff;
background-color: #10b981;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
}
.back-button:hover {
background-color: #059669;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}
.back-button:active {
transform: translateY(0);
}
.back-button svg {
width: 18px;
height: 18px;
}
</style>