security: 实施 HttpOnly Cookie 鉴权方案
## 后端修改 - 新增 /api/logout 接口清除认证 Cookie ## 前端修改 - 移除 localStorage 存储 token/refreshToken(防止 XSS 窃取) - 移除所有手动 Authorization 头(共36处) - checkLoginStatus 改为直接调用 API 验证(Cookie 自动携带) - logout 改为调用后端接口清除 Cookie - 简化 token 刷新逻辑 ## 安全性提升 - Token 从 localStorage 迁移到 HttpOnly Cookie - XSS 攻击无法通过 JS 读取 token - 配合 SameSite 属性防御 CSRF 攻击 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1731,6 +1731,13 @@ app.post('/api/refresh-token', (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 登出(清除Cookie)
|
||||||
|
app.post('/api/logout', (req, res) => {
|
||||||
|
// 清除认证Cookie
|
||||||
|
res.clearCookie('token', { path: '/' });
|
||||||
|
res.json({ success: true, message: '已登出' });
|
||||||
|
});
|
||||||
|
|
||||||
// ===== 需要认证的API =====
|
// ===== 需要认证的API =====
|
||||||
|
|
||||||
// 获取当前用户信息
|
// 获取当前用户信息
|
||||||
|
|||||||
228
frontend/app.js
228
frontend/app.js
@@ -322,9 +322,7 @@ createApp({
|
|||||||
// 加载用户主题设置(登录后调用)
|
// 加载用户主题设置(登录后调用)
|
||||||
async loadUserTheme() {
|
async loadUserTheme() {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(`${this.apiBase}/api/user/theme`, {
|
const res = await axios.get(`${this.apiBase}/api/user/theme`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
if (res.data.success) {
|
if (res.data.success) {
|
||||||
this.globalTheme = res.data.theme.global;
|
this.globalTheme = res.data.theme.global;
|
||||||
this.userThemePreference = res.data.theme.user;
|
this.userThemePreference = res.data.theme.user;
|
||||||
@@ -352,7 +350,6 @@ createApp({
|
|||||||
try {
|
try {
|
||||||
const res = await axios.post(`${this.apiBase}/api/user/theme`,
|
const res = await axios.post(`${this.apiBase}/api/user/theme`,
|
||||||
{ theme },
|
{ theme },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` }}
|
|
||||||
);
|
);
|
||||||
if (res.data.success) {
|
if (res.data.success) {
|
||||||
this.userThemePreference = res.data.theme.user;
|
this.userThemePreference = res.data.theme.user;
|
||||||
@@ -378,7 +375,6 @@ createApp({
|
|||||||
console.log('[主题] 设置全局主题:', theme);
|
console.log('[主题] 设置全局主题:', theme);
|
||||||
const res = await axios.post(`${this.apiBase}/api/admin/settings`,
|
const res = await axios.post(`${this.apiBase}/api/admin/settings`,
|
||||||
{ global_theme: theme },
|
{ global_theme: theme },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` }}
|
|
||||||
);
|
);
|
||||||
console.log('[主题] API响应:', res.data);
|
console.log('[主题] API响应:', res.data);
|
||||||
if (res.data.success) {
|
if (res.data.success) {
|
||||||
@@ -542,9 +538,8 @@ handleDragLeave(e) {
|
|||||||
this.showCaptcha = false;
|
this.showCaptcha = false;
|
||||||
this.loginForm.captcha = '';
|
this.loginForm.captcha = '';
|
||||||
|
|
||||||
// 保存token到localStorage
|
// 保存用户信息到localStorage(非敏感信息,用于页面刷新后恢复)
|
||||||
localStorage.setItem('token', this.token);
|
// 注意:token 通过 HttpOnly Cookie 传递,不再存储在 localStorage
|
||||||
localStorage.setItem('refreshToken', this.refreshToken);
|
|
||||||
localStorage.setItem('user', JSON.stringify(this.user));
|
localStorage.setItem('user', JSON.stringify(this.user));
|
||||||
|
|
||||||
// 启动token自动刷新(在过期前5分钟刷新)
|
// 启动token自动刷新(在过期前5分钟刷新)
|
||||||
@@ -565,11 +560,8 @@ handleDragLeave(e) {
|
|||||||
console.log('[登录] SFTP未配置但用户有本地存储权限,自动切换到本地存储');
|
console.log('[登录] SFTP未配置但用户有本地存储权限,自动切换到本地存储');
|
||||||
this.storageType = 'local';
|
this.storageType = 'local';
|
||||||
// 异步更新到后端(不等待,避免阻塞登录流程)
|
// 异步更新到后端(不等待,避免阻塞登录流程)
|
||||||
axios.post(
|
axios.post(`${this.apiBase}/api/user/switch-storage`, { storage_type: 'local' })
|
||||||
`${this.apiBase}/api/user/switch-storage`,
|
.catch(err => console.error('[登录] 自动切换存储类型失败:', err));
|
||||||
{ storage_type: 'local' },
|
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
).catch(err => console.error('[登录] 自动切换存储类型失败:', err));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +747,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/user/update-ftp`,
|
`${this.apiBase}/api/user/update-ftp`,
|
||||||
this.ftpConfigForm,
|
this.ftpConfigForm,
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -769,8 +760,7 @@ handleDragLeave(e) {
|
|||||||
const switchResponse = await axios.post(
|
const switchResponse = await axios.post(
|
||||||
`${this.apiBase}/api/user/switch-storage`,
|
`${this.apiBase}/api/user/switch-storage`,
|
||||||
{ storage_type: 'sftp' },
|
{ storage_type: 'sftp' },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (switchResponse.data.success) {
|
if (switchResponse.data.success) {
|
||||||
this.storageType = 'sftp';
|
this.storageType = 'sftp';
|
||||||
@@ -800,18 +790,12 @@ handleDragLeave(e) {
|
|||||||
{
|
{
|
||||||
username: this.adminProfileForm.username
|
username: this.adminProfileForm.username
|
||||||
},
|
},
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
alert('用户名已更新!请重新登录。');
|
alert('用户名已更新!请重新登录。');
|
||||||
|
|
||||||
// 更新token和用户信息
|
// 更新用户信息(后端已通过 Cookie 更新 token)
|
||||||
if (response.data.token) {
|
|
||||||
this.token = response.data.token;
|
|
||||||
localStorage.setItem('token', response.data.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.data.user) {
|
if (response.data.user) {
|
||||||
this.user = response.data.user;
|
this.user = response.data.user;
|
||||||
localStorage.setItem('user', JSON.stringify(response.data.user));
|
localStorage.setItem('user', JSON.stringify(response.data.user));
|
||||||
@@ -843,7 +827,6 @@ handleDragLeave(e) {
|
|||||||
current_password: this.changePasswordForm.current_password,
|
current_password: this.changePasswordForm.current_password,
|
||||||
new_password: this.changePasswordForm.new_password
|
new_password: this.changePasswordForm.new_password
|
||||||
},
|
},
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -860,7 +843,6 @@ handleDragLeave(e) {
|
|||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`${this.apiBase}/api/user/profile`,
|
`${this.apiBase}/api/user/profile`,
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success && response.data.user) {
|
if (response.data.success && response.data.user) {
|
||||||
@@ -975,7 +957,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/user/update-username`,
|
`${this.apiBase}/api/user/update-username`,
|
||||||
{ username: this.usernameForm.newUsername },
|
{ username: this.usernameForm.newUsername },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -995,7 +976,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/user/update-profile`,
|
`${this.apiBase}/api/user/update-profile`,
|
||||||
{ email: this.profileForm.email },
|
{ email: this.profileForm.email },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1011,14 +991,19 @@ handleDragLeave(e) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
logout() {
|
async logout() {
|
||||||
|
// 调用后端清除 HttpOnly Cookie
|
||||||
|
try {
|
||||||
|
await axios.post(`${this.apiBase}/api/logout`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[登出] 清除Cookie失败:', err);
|
||||||
|
}
|
||||||
|
|
||||||
this.isLoggedIn = false;
|
this.isLoggedIn = false;
|
||||||
this.user = null;
|
this.user = null;
|
||||||
this.token = null;
|
this.token = null;
|
||||||
this.refreshToken = null;
|
this.refreshToken = null;
|
||||||
this.stopTokenRefresh();
|
this.stopTokenRefresh();
|
||||||
localStorage.removeItem('token');
|
|
||||||
localStorage.removeItem('refreshToken');
|
|
||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
localStorage.removeItem('lastView');
|
localStorage.removeItem('lastView');
|
||||||
this.showResendVerify = false;
|
this.showResendVerify = false;
|
||||||
@@ -1041,82 +1026,61 @@ handleDragLeave(e) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 检查本地存储的登录状态
|
// 检查登录状态(通过 HttpOnly Cookie 验证)
|
||||||
async checkLoginStatus() {
|
async checkLoginStatus() {
|
||||||
const token = localStorage.getItem('token');
|
// 直接调用API验证,Cookie会自动携带
|
||||||
const refreshToken = localStorage.getItem('refreshToken');
|
try {
|
||||||
const user = localStorage.getItem('user');
|
const response = await axios.get(`${this.apiBase}/api/user/profile`);
|
||||||
|
|
||||||
if (token && user) {
|
if (response.data.success && response.data.user) {
|
||||||
this.token = token;
|
// Cookie有效,用户已登录
|
||||||
this.refreshToken = refreshToken;
|
this.user = response.data.user;
|
||||||
this.user = JSON.parse(user);
|
this.isLoggedIn = true;
|
||||||
|
|
||||||
// 先验证token是否有效
|
// 更新localStorage中的用户信息(非敏感信息)
|
||||||
try {
|
localStorage.setItem('user', JSON.stringify(this.user));
|
||||||
const response = await axios.get(
|
|
||||||
`${this.apiBase}/api/user/profile`,
|
|
||||||
{ headers: { Authorization: `Bearer ${token}` } }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.data.success && response.data.user) {
|
// 从最新的用户信息初始化存储相关字段
|
||||||
// token有效,更新用户信息
|
this.storagePermission = this.user.storage_permission || 'sftp_only';
|
||||||
this.user = response.data.user;
|
this.storageType = this.user.current_storage_type || 'sftp';
|
||||||
this.isLoggedIn = true;
|
this.localQuota = this.user.local_storage_quota || 0;
|
||||||
|
this.localUsed = this.user.local_storage_used || 0;
|
||||||
|
|
||||||
// 更新localStorage中的用户信息
|
console.log('[页面加载] Cookie验证成功,存储权限:', this.storagePermission, '存储类型:', this.storageType);
|
||||||
localStorage.setItem('user', JSON.stringify(this.user));
|
|
||||||
|
|
||||||
// 从最新的用户信息初始化存储相关字段
|
// 启动token自动刷新(假设剩余1.5小时,实际由服务端控制)
|
||||||
this.storagePermission = this.user.storage_permission || 'sftp_only';
|
this.startTokenRefresh(1.5 * 60 * 60 * 1000);
|
||||||
this.storageType = this.user.current_storage_type || 'sftp';
|
|
||||||
this.localQuota = this.user.local_storage_quota || 0;
|
|
||||||
this.localUsed = this.user.local_storage_used || 0;
|
|
||||||
|
|
||||||
console.log('[页面加载] Token验证成功,存储权限:', this.storagePermission, '存储类型:', this.storageType);
|
// 启动定期检查用户配置
|
||||||
|
this.startProfileSync();
|
||||||
|
// 加载用户主题设置
|
||||||
|
this.loadUserTheme();
|
||||||
|
|
||||||
// 启动token自动刷新(假设剩余1.5小时,实际由服务端控制)
|
// 读取上次停留的视图(需合法才生效)
|
||||||
this.startTokenRefresh(1.5 * 60 * 60 * 1000);
|
const savedView = localStorage.getItem('lastView');
|
||||||
|
let targetView = null;
|
||||||
// 启动定期检查用户配置
|
if (savedView && this.isViewAllowed(savedView)) {
|
||||||
this.startProfileSync();
|
targetView = savedView;
|
||||||
// 加载用户主题设置
|
} else if (this.user.is_admin) {
|
||||||
this.loadUserTheme();
|
targetView = 'admin';
|
||||||
|
} else if (this.storagePermission === 'sftp_only' && !this.user.has_ftp_config) {
|
||||||
// 读取上次停留的视图(需合法才生效)
|
targetView = 'settings';
|
||||||
const savedView = localStorage.getItem('lastView');
|
|
||||||
let targetView = null;
|
|
||||||
if (savedView && this.isViewAllowed(savedView)) {
|
|
||||||
targetView = savedView;
|
|
||||||
} else if (this.user.is_admin) {
|
|
||||||
targetView = 'admin';
|
|
||||||
} else if (this.storagePermission === 'sftp_only' && !this.user.has_ftp_config) {
|
|
||||||
targetView = 'settings';
|
|
||||||
} else {
|
|
||||||
targetView = 'files';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 强制切换到目标视图并加载数据
|
|
||||||
this.switchView(targetView, true);
|
|
||||||
} else {
|
} else {
|
||||||
// 响应异常,尝试刷新token
|
targetView = 'files';
|
||||||
await this.tryRefreshOrLogout();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.warn('[页面加载] Token验证失败:', error.response?.status || error.message);
|
// 强制切换到目标视图并加载数据
|
||||||
// token无效或过期,尝试使用refresh token刷新
|
this.switchView(targetView, true);
|
||||||
if (error.response?.status === 401 && this.refreshToken) {
|
|
||||||
console.log('[页面加载] 尝试使用refresh token刷新...');
|
|
||||||
const refreshed = await this.doRefreshToken();
|
|
||||||
if (refreshed) {
|
|
||||||
// 刷新成功,重新检查登录状态
|
|
||||||
await this.checkLoginStatus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 刷新失败或无refresh token,清除登录状态
|
|
||||||
this.handleTokenExpired();
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 401表示未登录或Cookie过期,静默处理(用户需要重新登录)
|
||||||
|
if (error.response?.status === 401) {
|
||||||
|
console.log('[页面加载] 未登录或Cookie已过期');
|
||||||
|
} else {
|
||||||
|
console.warn('[页面加载] 验证登录状态失败:', error.message);
|
||||||
|
}
|
||||||
|
// 清理可能残留的用户信息
|
||||||
|
localStorage.removeItem('user');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1134,14 +1098,12 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
// 处理token过期/失效
|
// 处理token过期/失效
|
||||||
handleTokenExpired() {
|
handleTokenExpired() {
|
||||||
console.log('[认证] Token已失效,清除登录状态');
|
console.log('[认证] Cookie已失效,清除登录状态');
|
||||||
this.isLoggedIn = false;
|
this.isLoggedIn = false;
|
||||||
this.user = null;
|
this.user = null;
|
||||||
this.token = null;
|
this.token = null;
|
||||||
this.refreshToken = null;
|
this.refreshToken = null;
|
||||||
this.stopTokenRefresh();
|
this.stopTokenRefresh();
|
||||||
localStorage.removeItem('token');
|
|
||||||
localStorage.removeItem('refreshToken');
|
|
||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
localStorage.removeItem('lastView');
|
localStorage.removeItem('lastView');
|
||||||
this.stopProfileSync();
|
this.stopProfileSync();
|
||||||
@@ -1168,7 +1130,7 @@ handleDragLeave(e) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 执行token刷新
|
// 执行token刷新(通过 refreshToken 刷新 HttpOnly Cookie 中的 access token)
|
||||||
async doRefreshToken() {
|
async doRefreshToken() {
|
||||||
if (!this.refreshToken) {
|
if (!this.refreshToken) {
|
||||||
console.log('[认证] 无refresh token,无法刷新');
|
console.log('[认证] 无refresh token,无法刷新');
|
||||||
@@ -1182,9 +1144,8 @@ handleDragLeave(e) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.token = response.data.token;
|
// 后端已自动更新 HttpOnly Cookie 中的 token
|
||||||
localStorage.setItem('token', this.token);
|
console.log('[认证] Token刷新成功(Cookie已更新)');
|
||||||
console.log('[认证] Token刷新成功');
|
|
||||||
|
|
||||||
// 继续下一次刷新
|
// 继续下一次刷新
|
||||||
const expiresIn = response.data.expiresIn || (2 * 60 * 60 * 1000);
|
const expiresIn = response.data.expiresIn || (2 * 60 * 60 * 1000);
|
||||||
@@ -1220,8 +1181,7 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBase}/api/files`, {
|
const response = await axios.get(`${this.apiBase}/api/files`, {
|
||||||
params: { path },
|
params: { path }
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1325,7 +1285,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/files/rename`,
|
`${this.apiBase}/api/files/rename`,
|
||||||
this.renameForm,
|
this.renameForm,
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1358,8 +1317,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(`${this.apiBase}/api/files/mkdir`, {
|
const response = await axios.post(`${this.apiBase}/api/files/mkdir`, {
|
||||||
path: this.currentPath,
|
path: this.currentPath,
|
||||||
folderName: folderName
|
folderName: folderName
|
||||||
}, {
|
|
||||||
headers: { 'Authorization': `Bearer ${this.token}` }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1388,8 +1345,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(`${this.apiBase}/api/files/folder-info`, {
|
const response = await axios.post(`${this.apiBase}/api/files/folder-info`, {
|
||||||
path: this.currentPath,
|
path: this.currentPath,
|
||||||
folderName: file.name
|
folderName: file.name
|
||||||
}, {
|
|
||||||
headers: { 'Authorization': `Bearer ${this.token}` }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1614,7 +1569,6 @@ handleDragLeave(e) {
|
|||||||
path: this.currentPath,
|
path: this.currentPath,
|
||||||
isDirectory: file.isDirectory
|
isDirectory: file.isDirectory
|
||||||
},
|
},
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1680,7 +1634,6 @@ handleDragLeave(e) {
|
|||||||
password: this.shareAllForm.password || null,
|
password: this.shareAllForm.password || null,
|
||||||
expiry_days: expiryDays
|
expiry_days: expiryDays
|
||||||
},
|
},
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1712,7 +1665,6 @@ handleDragLeave(e) {
|
|||||||
password: this.shareFileForm.password || null,
|
password: this.shareFileForm.password || null,
|
||||||
expiry_days: expiryDays
|
expiry_days: expiryDays
|
||||||
},
|
},
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -1798,7 +1750,6 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
const response = await axios.post(`${this.apiBase}/api/upload`, formData, {
|
const response = await axios.post(`${this.apiBase}/api/upload`, formData, {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${this.token}`,
|
|
||||||
'Content-Type': 'multipart/form-data'
|
'Content-Type': 'multipart/form-data'
|
||||||
},
|
},
|
||||||
timeout: 30 * 60 * 1000, // 30分钟超时,支持大文件上传
|
timeout: 30 * 60 * 1000, // 30分钟超时,支持大文件上传
|
||||||
@@ -1864,9 +1815,7 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
async loadShares() {
|
async loadShares() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBase}/api/share/my`, {
|
const response = await axios.get(`${this.apiBase}/api/share/my`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.shares = response.data.shares;
|
this.shares = response.data.shares;
|
||||||
@@ -1881,9 +1830,7 @@ handleDragLeave(e) {
|
|||||||
this.shareForm.path = this.currentPath;
|
this.shareForm.path = this.currentPath;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(`${this.apiBase}/api/share/create`, this.shareForm, {
|
const response = await axios.post(`${this.apiBase}/api/share/create`, this.shareForm);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.shareResult = response.data;
|
this.shareResult = response.data;
|
||||||
@@ -1899,9 +1846,7 @@ handleDragLeave(e) {
|
|||||||
if (!confirm('确定要删除这个分享吗?')) return;
|
if (!confirm('确定要删除这个分享吗?')) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.delete(`${this.apiBase}/api/share/${id}`, {
|
const response = await axios.delete(`${this.apiBase}/api/share/${id}`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
alert('分享已删除');
|
alert('分享已删除');
|
||||||
@@ -2000,9 +1945,7 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
async loadUsers() {
|
async loadUsers() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBase}/api/admin/users`, {
|
const response = await axios.get(`${this.apiBase}/api/admin/users`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.adminUsers = response.data.users;
|
this.adminUsers = response.data.users;
|
||||||
@@ -2021,7 +1964,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/admin/users/${userId}/ban`,
|
`${this.apiBase}/api/admin/users/${userId}/ban`,
|
||||||
{ banned },
|
{ banned },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2038,9 +1980,7 @@ handleDragLeave(e) {
|
|||||||
if (!confirm('确定要删除这个用户吗?此操作不可恢复!')) return;
|
if (!confirm('确定要删除这个用户吗?此操作不可恢复!')) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.delete(`${this.apiBase}/api/admin/users/${userId}`, {
|
const response = await axios.delete(`${this.apiBase}/api/admin/users/${userId}`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
alert('用户已删除');
|
alert('用户已删除');
|
||||||
@@ -2123,8 +2063,7 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`${this.apiBase}/api/admin/users/${this.inspectionUser.id}/files`,
|
`${this.apiBase}/api/admin/users/${this.inspectionUser.id}/files`,
|
||||||
{
|
{
|
||||||
params: { path },
|
params: { path }
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2166,7 +2105,6 @@ handleDragLeave(e) {
|
|||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`${this.apiBase}/api/user/profile`,
|
`${this.apiBase}/api/user/profile`,
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success && response.data.user) {
|
if (response.data.success && response.data.user) {
|
||||||
@@ -2228,7 +2166,6 @@ handleDragLeave(e) {
|
|||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`${this.apiBase}/api/user/sftp-usage`,
|
`${this.apiBase}/api/user/sftp-usage`,
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2287,7 +2224,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/user/switch-storage`,
|
`${this.apiBase}/api/user/switch-storage`,
|
||||||
{ storage_type: type },
|
{ storage_type: type },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2426,7 +2362,6 @@ handleDragLeave(e) {
|
|||||||
storage_permission: this.editStorageForm.storage_permission,
|
storage_permission: this.editStorageForm.storage_permission,
|
||||||
local_storage_quota: quotaBytes
|
local_storage_quota: quotaBytes
|
||||||
},
|
},
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2506,9 +2441,7 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
async loadSystemSettings() {
|
async loadSystemSettings() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBase}/api/admin/settings`, {
|
const response = await axios.get(`${this.apiBase}/api/admin/settings`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
const settings = response.data.settings;
|
const settings = response.data.settings;
|
||||||
@@ -2537,9 +2470,7 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
async loadServerStorageStats() {
|
async loadServerStorageStats() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBase}/api/admin/storage-stats`, {
|
const response = await axios.get(`${this.apiBase}/api/admin/storage-stats`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.serverStorageStats = response.data.stats;
|
this.serverStorageStats = response.data.stats;
|
||||||
@@ -2570,8 +2501,7 @@ handleDragLeave(e) {
|
|||||||
|
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/admin/settings`,
|
`${this.apiBase}/api/admin/settings`,
|
||||||
payload,
|
payload
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2590,7 +2520,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/admin/settings/test-smtp`,
|
`${this.apiBase}/api/admin/settings/test-smtp`,
|
||||||
{ to: this.systemSettings.smtp.user },
|
{ to: this.systemSettings.smtp.user },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
this.showToast('success', '成功', response.data.message || '测试邮件已发送');
|
this.showToast('success', '成功', response.data.message || '测试邮件已发送');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -2604,9 +2533,7 @@ handleDragLeave(e) {
|
|||||||
async loadHealthCheck() {
|
async loadHealthCheck() {
|
||||||
this.healthCheck.loading = true;
|
this.healthCheck.loading = true;
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBase}/api/admin/health-check`, {
|
const response = await axios.get(`${this.apiBase}/api/admin/health-check`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.healthCheck.overallStatus = response.data.overallStatus;
|
this.healthCheck.overallStatus = response.data.overallStatus;
|
||||||
@@ -2680,9 +2607,7 @@ handleDragLeave(e) {
|
|||||||
params.append('keyword', this.systemLogs.filters.keyword);
|
params.append('keyword', this.systemLogs.filters.keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await axios.get(`${this.apiBase}/api/admin/logs?${params}`, {
|
const response = await axios.get(`${this.apiBase}/api/admin/logs?${params}`);
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.systemLogs.logs = response.data.logs;
|
this.systemLogs.logs = response.data.logs;
|
||||||
@@ -2766,7 +2691,6 @@ handleDragLeave(e) {
|
|||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${this.apiBase}/api/admin/logs/cleanup`,
|
`${this.apiBase}/api/admin/logs/cleanup`,
|
||||||
{ keepDays: 90 },
|
{ keepDays: 90 },
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2787,7 +2711,6 @@ handleDragLeave(e) {
|
|||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`${this.apiBase}/api/admin/check-upload-tool`,
|
`${this.apiBase}/api/admin/check-upload-tool`,
|
||||||
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
@@ -2844,7 +2767,6 @@ handleDragLeave(e) {
|
|||||||
formData,
|
formData,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${this.token}`,
|
|
||||||
'Content-Type': 'multipart/form-data'
|
'Content-Type': 'multipart/form-data'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user