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