- 数据库用户模型新增登录失败限制相关字段(login_failed_count, last_failed_login, login_locked_until) - 增加用户方法判断是否处于登录锁定状态及计算锁定持续时间 - 登录接口新增登录锁定检测,密码错误时增加失败计数及设置锁定时间 - 登录成功时重置失败计数和锁定状态 - 新增数据库迁移模块,自动检测并执行数据库结构更新,确保新增字段同步 - 前端登录页添加账户锁定状态显示及倒计时功能 - 前端请求中捕获423锁定状态,展示对应锁定提示,禁用登录按钮 - 优化本地状态管理,支持登录锁定错误抛出与异常处理机制
259 lines
6.4 KiB
JavaScript
259 lines
6.4 KiB
JavaScript
import { defineStore } from 'pinia'
|
||
import { ref, computed } from 'vue'
|
||
|
||
export const useUserStore = defineStore('user', () => {
|
||
// 状态
|
||
const token = ref(localStorage.getItem('user_token') || '')
|
||
const userId = ref(parseInt(localStorage.getItem('user_id') || '0') || null)
|
||
const username = ref(localStorage.getItem('username') || '')
|
||
const userRole = ref(localStorage.getItem('user_role') || '')
|
||
|
||
// 计算属性
|
||
const isLoggedIn = computed(() => !!token.value)
|
||
const isAdmin = computed(() => userRole.value === 'admin' || userRole.value === 'superadmin')
|
||
const isSuperAdmin = computed(() => userRole.value === 'superadmin')
|
||
|
||
// 动作
|
||
async function login(credentials) {
|
||
try {
|
||
const formData = new FormData()
|
||
formData.append('username', credentials.username)
|
||
formData.append('password', credentials.password)
|
||
|
||
const response = await fetch('/api/auth/token', {
|
||
method: 'POST',
|
||
body: formData
|
||
})
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json()
|
||
|
||
// 如果是423锁定状态码,抛出包含状态码的错误
|
||
if (response.status === 423) {
|
||
const lockError = new Error(error.detail || '账户被锁定')
|
||
lockError.status = 423
|
||
lockError.headers = response.headers
|
||
throw lockError
|
||
}
|
||
|
||
throw new Error(error.detail || '登录失败')
|
||
}
|
||
|
||
const data = await response.json()
|
||
|
||
// 更新状态
|
||
token.value = data.access_token
|
||
userId.value = data.user_id
|
||
username.value = data.username
|
||
userRole.value = data.role
|
||
|
||
// 保存到本地存储
|
||
localStorage.setItem('user_token', data.access_token)
|
||
localStorage.setItem('user_id', data.user_id)
|
||
localStorage.setItem('username', data.username)
|
||
localStorage.setItem('user_role', data.role)
|
||
|
||
return true
|
||
} catch (error) {
|
||
console.error('登录错误:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
function logout() {
|
||
// 清除状态
|
||
token.value = ''
|
||
userId.value = null
|
||
username.value = ''
|
||
userRole.value = ''
|
||
|
||
// 清除本地存储
|
||
localStorage.removeItem('user_token')
|
||
localStorage.removeItem('user_id')
|
||
localStorage.removeItem('username')
|
||
localStorage.removeItem('user_role')
|
||
}
|
||
|
||
async function initialize(admin) {
|
||
try {
|
||
const response = await fetch('/api/auth/initialize', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(admin)
|
||
})
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json()
|
||
throw new Error(error.detail || '初始化管理员失败')
|
||
}
|
||
|
||
const data = await response.json()
|
||
|
||
// 更新状态
|
||
token.value = data.access_token
|
||
userId.value = data.user_id
|
||
username.value = data.username
|
||
userRole.value = data.role
|
||
|
||
// 保存到本地存储
|
||
localStorage.setItem('user_token', data.access_token)
|
||
localStorage.setItem('user_id', data.user_id)
|
||
localStorage.setItem('username', data.username)
|
||
localStorage.setItem('user_role', data.role)
|
||
|
||
return true
|
||
} catch (error) {
|
||
console.error('初始化管理员错误:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
async function checkFirstRun() {
|
||
try {
|
||
const response = await fetch('/api/auth/check-first-run')
|
||
const data = await response.json()
|
||
return data.first_run
|
||
} catch (error) {
|
||
console.error('检查首次运行状态错误:', error)
|
||
return false
|
||
}
|
||
}
|
||
|
||
// 用于API请求的授权头
|
||
function getAuthHeaders() {
|
||
return {
|
||
'Authorization': `Bearer ${token.value}`
|
||
}
|
||
}
|
||
|
||
// 用户管理功能
|
||
async function getUsers() {
|
||
try {
|
||
const response = await fetch('/api/auth/users', {
|
||
headers: {
|
||
...getAuthHeaders()
|
||
}
|
||
})
|
||
|
||
if (!response.ok) {
|
||
throw new Error('获取用户列表失败')
|
||
}
|
||
|
||
return await response.json()
|
||
} catch (error) {
|
||
console.error('获取用户列表错误:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
async function createUser(userData) {
|
||
try {
|
||
const response = await fetch('/api/auth/users', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
...getAuthHeaders()
|
||
},
|
||
body: JSON.stringify(userData)
|
||
})
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json()
|
||
throw new Error(error.detail || '创建用户失败')
|
||
}
|
||
|
||
return await response.json()
|
||
} catch (error) {
|
||
console.error('创建用户错误:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
async function updateUser(userId, userData) {
|
||
try {
|
||
const response = await fetch(`/api/auth/users/${userId}`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
...getAuthHeaders()
|
||
},
|
||
body: JSON.stringify(userData)
|
||
})
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json()
|
||
throw new Error(error.detail || '更新用户失败')
|
||
}
|
||
|
||
return await response.json()
|
||
} catch (error) {
|
||
console.error('更新用户错误:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
async function deleteUser(userId) {
|
||
try {
|
||
const response = await fetch(`/api/auth/users/${userId}`, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
...getAuthHeaders()
|
||
}
|
||
})
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json()
|
||
throw new Error(error.detail || '删除用户失败')
|
||
}
|
||
|
||
return await response.json()
|
||
} catch (error) {
|
||
console.error('删除用户错误:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
return {
|
||
// 状态
|
||
token,
|
||
userId,
|
||
username,
|
||
userRole,
|
||
|
||
// 计算属性
|
||
isLoggedIn,
|
||
isAdmin,
|
||
isSuperAdmin,
|
||
|
||
// 方法
|
||
login,
|
||
logout,
|
||
initialize,
|
||
checkFirstRun,
|
||
getAuthHeaders,
|
||
getUsers,
|
||
createUser,
|
||
updateUser,
|
||
deleteUser
|
||
}
|
||
})
|
||
|
||
// 检查当前用户是否有管理员权限
|
||
export const checkAdminPermission = () => {
|
||
const userStore = useUserStore()
|
||
if (!userStore.isAdmin) {
|
||
throw new Error('需要管理员权限')
|
||
}
|
||
return true
|
||
}
|
||
|
||
// 检查当前用户是否有超级管理员权限
|
||
export const checkSuperAdminPermission = () => {
|
||
const userStore = useUserStore()
|
||
if (!userStore.isSuperAdmin) {
|
||
throw new Error('需要超级管理员权限')
|
||
}
|
||
return true
|
||
} |