✨ 添加登录验证码功能 - 增强系统安全性
## 新增功能 - 密码输错2次后自动显示验证码 - 4位数字验证码,点击可刷新 - 验证码有效期5分钟 - 基于IP和用户名双重防护 - 前台和后台登录均支持 ## 后端改动 - 新增验证码生成API: GET /api/captcha - 修改登录API支持验证码验证 - 添加session管理验证码 - 增强RateLimiter防爆破机制 ## 前端改动 - 登录表单添加验证码输入框(条件显示) - 验证码图片展示和刷新功能 - 自动触发验证码显示逻辑 ## 依赖更新 - 新增: svg-captcha (验证码生成) - 新增: express-session (session管理) ## 文档 - CAPTCHA_FEATURE.md - 详细功能文档 - CAPTCHA_README.md - 快速开始指南 - test_captcha.sh - 自动化测试脚本 - 更新说明_验证码功能.txt - 中文说明 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -672,6 +672,16 @@
|
||||
<label class="form-label">密码</label>
|
||||
<input type="password" class="form-input" v-model="loginForm.password" required>
|
||||
</div>
|
||||
<div v-if="showCaptcha" class="form-group">
|
||||
<label class="form-label">验证码</label>
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<input type="text" class="form-input" v-model="loginForm.captcha" required style="flex: 1;" placeholder="请输入验证码">
|
||||
<div style="cursor: pointer; border: 1px solid #ddd; border-radius: 4px; padding: 5px; background: #f0f0f0;" @click="refreshCaptcha">
|
||||
<img :src="captchaUrl" alt="验证码" style="display: block; width: 120px; height: 40px;" />
|
||||
</div>
|
||||
</div>
|
||||
<small style="color: #666; font-size: 12px;">点击图片刷新验证码</small>
|
||||
</div>
|
||||
<div style="text-align: right; margin-bottom: 15px;">
|
||||
<a @click="showForgotPasswordModal = true" style="color: #667eea; cursor: pointer; font-size: 14px; text-decoration: none;">
|
||||
忘记密码?
|
||||
|
||||
@@ -22,7 +22,8 @@ createApp({
|
||||
// 表单数据
|
||||
loginForm: {
|
||||
username: '',
|
||||
password: ''
|
||||
password: '',
|
||||
captcha: ''
|
||||
},
|
||||
registerForm: {
|
||||
username: '',
|
||||
@@ -30,6 +31,10 @@ createApp({
|
||||
password: ''
|
||||
},
|
||||
|
||||
// 验证码相关
|
||||
showCaptcha: false,
|
||||
captchaUrl: '',
|
||||
|
||||
// SFTP配置表单
|
||||
ftpConfigForm: {
|
||||
ftp_host: '',
|
||||
@@ -321,6 +326,10 @@ handleDragLeave(e) {
|
||||
this.user = response.data.user;
|
||||
this.isLoggedIn = true;
|
||||
|
||||
// 登录成功后隐藏验证码并清空验证码输入
|
||||
this.showCaptcha = false;
|
||||
this.loginForm.captcha = '';
|
||||
|
||||
// 保存token到localStorage
|
||||
localStorage.setItem('token', this.token);
|
||||
localStorage.setItem('user', JSON.stringify(this.user));
|
||||
@@ -378,9 +387,20 @@ handleDragLeave(e) {
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorMessage = error.response?.data?.message || '登录失败';
|
||||
|
||||
// 检查是否需要显示验证码
|
||||
if (error.response?.data?.needCaptcha) {
|
||||
this.showCaptcha = true;
|
||||
this.refreshCaptcha();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新验证码
|
||||
refreshCaptcha() {
|
||||
this.captchaUrl = `${this.apiBase}/api/captcha?t=${Date.now()}`;
|
||||
},
|
||||
|
||||
async handleRegister() {
|
||||
this.errorMessage = '';
|
||||
this.successMessage = '';
|
||||
|
||||
Reference in New Issue
Block a user