大型后台管理系统的用户登录状态保存需要综合考虑安全性、用户体验和系统架构。以下是企业级的完整方案:
class AuthManager {
constructor() {
this.storage = {
// 内存存储(最高安全)
memory: new Map(),
// 会话级存储(较高安全)
session: sessionStorage,
// 持久化存储(用户偏好)
local: localStorage,
// 自动传输存储(兼容性)
cookie: this.cookieManager
}
}
// 分级存储策略
setLoginState(userData) {
// 1. 敏感数据 - 内存存储(刷新即失)
this.storage.memory.set('access_token', userData.accessToken)
this.storage.memory.set('session_key', userData.sessionKey)
// 2. 刷新令牌 - HttpOnly Cookie(防XSS)
this.setHttpOnlyCookie('refresh_token', userData.refreshToken, {
maxAge: 7 * 24 * 60 * 60, // 7天
httpOnly: true,
secure: true,
sameSite: 'strict'
})
// 3. 用户基本信息 - localStorage(持久化)
this.storage.local.setItem('user_info', JSON.stringify({
id: userData.id,
name: userData.name,
avatar: userData.avatar,
roles: userData.roles,
permissions: userData.permissions
}))
// 4. 登录状态标识 - sessionStorage(标签页级)
this.storage.session.setItem('is_logged_in', 'true')
this.storage.session.setItem('login_timestamp', Date.now())
// 5. 辅助信息 - 普通Cookie
this.setCookie('user_theme', userData.theme, { maxAge: 30 * 24 * 60 * 60 })
}
}class TokenService {
constructor() {
this.accessToken = null
this.refreshToken = null
this.tokenRefreshTimeout = null
}
// 设置双令牌
setTokens(accessToken, refreshToken) {
// Access Token - 短期(内存 + 备用localStorage)
this.accessToken = accessToken
localStorage.setItem('access_token_backup', accessToken)
localStorage.setItem('access_token_expire', Date.now() + 2 * 60 * 60 * 1000) // 2小时
// Refresh Token - 长期(HttpOnly Cookie)
this.setHttpOnlyCookie('refresh_token', refreshToken, {
maxAge: 7 * 24 * 60 * 60,
httpOnly: true,
secure: true
})
// 启动token自动刷新
this.startTokenRefresh()
}
// 自动刷新token
startTokenRefresh() {
// 在token过期前5分钟自动刷新
const refreshTime = 115 * 60 * 1000 // 115分钟
this.tokenRefreshTimeout = setTimeout(async () => {
try {
await this.refreshAccessToken()
} catch (error) {
console.error('Token自动刷新失败:', error)
this.handleTokenRefreshFailed()
}
}, refreshTime)
}
// 刷新access token
async refreshAccessToken() {
const refreshToken = this.getRefreshToken()
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ refreshToken })
})
if (response.ok) {
const data = await response.json()
this.setTokens(data.accessToken, data.refreshToken)
return data.accessToken
} else {
throw new Error('刷新token失败')
}
}
}class AppInitializer {
constructor() {
this.authManager = new AuthManager()
this.tokenService = new TokenService()
}
// 应用启动时恢复登录状态
async initializeApp() {
console.log('🚀 应用初始化...')
// 1. 检查内存中的token(最高优先级)
if (this.tokenService.accessToken) {
console.log('✅ 内存中存在有效token')
return await this.validateCurrentToken()
}
// 2. 检查备份的access token
const backupToken = localStorage.getItem('access_token_backup')
const tokenExpire = localStorage.getItem('access_token_expire')
if (backupToken && tokenExpire && Date.now() < parseInt(tokenExpire)) {
console.log('✅ 使用备份token恢复')
this.tokenService.accessToken = backupToken
return await this.validateCurrentToken()
}
// 3. 尝试使用refresh token刷新
if (this.getRefreshToken()) {
console.log('🔄 尝试刷新token...')
try {
await this.tokenService.refreshAccessToken()
return await this.validateCurrentToken()
} catch (error) {
console.log('❌ token刷新失败')
this.clearAuthState()
}
}
// 4. 最终检查session状态
if (sessionStorage.getItem('is_logged_in') === 'true') {
console.log('🔍 会话状态存在,但token无效')
// 可能需要重新认证
}
// 5. 未登录状态
console.log('🔒 用户未登录')
this.redirectToLogin()
}
// 验证当前token有效性
async validateCurrentToken() {
try {
const response = await fetch('/api/auth/validate', {
headers: {
'Authorization': `Bearer ${this.tokenService.accessToken}`
}
})
if (response.ok) {
const userData = await response.json()
this.authManager.setUserData(userData)
console.log('✅ 登录状态验证成功')
return true
} else {
throw new Error('Token验证失败')
}
} catch (error) {
console.error('❌ Token验证失败:', error)
this.clearAuthState()
return false
}
}
}// axios请求拦截配置
import axios from 'axios'
class RequestInterceptor {
constructor() {
this.setupInterceptors()
}
setupInterceptors() {
// 请求拦截器
axios.interceptors.request.use(
(config) => {
const token = this.getAccessToken()
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error)
)
// 响应拦截器 - 处理认证失败
axios.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config
// 处理401错误(未认证)
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
try {
// 尝试刷新token
const newToken = await this.tokenService.refreshAccessToken()
originalRequest.headers.Authorization = `Bearer ${newToken}`
return axios(originalRequest)
} catch (refreshError) {
// 刷新失败,清除登录状态
this.clearAuthState()
this.redirectToLogin()
return Promise.reject(refreshError)
}
}
// 处理403错误(权限不足)
if (error.response?.status === 403) {
this.showPermissionDenied()
return Promise.reject(error)
}
return Promise.reject(error)
}
)
}
}class SecurityEnhancer {
constructor() {
this.setupSecurityMeasures()
}
setupSecurityMeasures() {
// 1. 防止XSS攻击
this.sanitizeStorage()
// 2. 设置安全头
this.setSecurityHeaders()
// 3. 监听异常行为
this.setupBehaviorMonitoring()
}
// 存储数据清理
sanitizeStorage() {
// 定期清理过期的存储数据
setInterval(() => {
this.cleanExpiredStorage()
}, 60 * 60 * 1000) // 每小时清理一次
}
// 行为监控
setupBehaviorMonitoring() {
// 监听多标签页登录冲突
window.addEventListener('storage', (event) => {
if (event.key === 'login_conflict' && event.newValue) {
this.handleLoginConflict()
}
})
// 监听用户活跃度
this.setupActivityMonitoring()
}
// 用户活跃度监控
setupActivityMonitoring() {
let lastActivityTime = Date.now()
const updateActivityTime = () => {
lastActivityTime = Date.now()
}
// 监听用户操作
['mousedown', 'keypress', 'scroll', 'touchstart'].forEach(event => {
document.addEventListener(event, updateActivityTime, true)
})
// 检查用户是否活跃
setInterval(() => {
const inactiveTime = Date.now() - lastActivityTime
if (inactiveTime > 30 * 60 * 1000) { // 30分钟无操作
this.handleUserInactive()
}
}, 60 * 1000) // 每分钟检查一次
}
}// 主入口文件 - main.js
import { createApp } from 'vue'
import App from './App.vue'
import { AuthManager, TokenService, AppInitializer } from './services/auth'
const app = createApp(App)
// 初始化认证服务
const authManager = new AuthManager()
const tokenService = new TokenService()
const appInitializer = new AppInitializer(authManager, tokenService)
// 全局提供认证服务
app.provide('authManager', authManager)
app.provide('tokenService', tokenService)
// 应用启动
appInitializer.initializeApp().then((isAuthenticated) => {
if (isAuthenticated) {
console.log('✅ 应用启动完成 - 用户已登录')
app.mount('#app')
} else {
console.log('🔒 应用启动完成 - 用户未登录')
// 可以挂载应用但显示登录界面
app.mount('#app')
}
}).catch((error) => {
console.error('❌ 应用启动失败:', error)
// 错误处理
})// 安全等级配置
export const SECURITY_LEVELS = {
// 金融级安全
FINANCE: {
accessTokenExpire: 15 * 60, // 15分钟
refreshTokenExpire: 24 * 60 * 60, // 24小时
autoLogout: 30 * 60, // 30分钟无操作自动登出
multiFactorAuth: true,
sessionPerDevice: true
},
// 企业级安全
ENTERPRISE: {
accessTokenExpire: 2 * 60 * 60, // 2小时
refreshTokenExpire: 7 * 24 * 60 * 60, // 7天
autoLogout: 60 * 60, // 1小时无操作
multiFactorAuth: false,
sessionPerDevice: false
},
// 内部系统
INTERNAL: {
accessTokenExpire: 8 * 60 * 60, // 8小时
refreshTokenExpire: 30 * 24 * 60 * 60, // 30天
autoLogout: 4 * 60 * 60, // 4小时无操作
multiFactorAuth: false,
rememberMe: true
}
}大型后台管理系统的登录状态管理应该是:
分层存储:敏感数据存内存,持久数据存localStorage,自动传输用Cookie
双令牌机制:短期access token + 长期refresh token
自动恢复:应用启动时智能恢复登录状态
安全增强:XSS防护、行为监控、自动登出
错误处理:完善的token刷新和错误处理机制
灵活配置:根据不同安全需求调整策略
这样的设计既保证了安全性,又提供了良好的用户体验。




B2C电商系统商城源码支持pC+小程序+公众号+H5可打包App源...
原生开发淘宝客App,Android+ios独立开发,全开源支持二...
知识付费系统在线教育平台源码+题库系统源码,PC+公众号商业授权...
B2C单商户电商系统源码部署小程序+公众号+H5+App源码...
教育知识付费系统源码带题库功能商业授权公众号+H5源码...