feat: adjust deploy password and login limit
This commit is contained in:
+1
-1
@@ -6,6 +6,6 @@
|
|||||||
|
|
||||||
启动后访问:http://localhost:8052
|
启动后访问:http://localhost:8052
|
||||||
|
|
||||||
默认账号:`admin` / `123456`
|
默认账号:用户名 `admin`,密码见启动日志(首次启动随机生成)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
### 最近更新
|
### 最近更新
|
||||||
|
|
||||||
|
**2026.02.11** - 增强安全性:首次启动使用随机密码并打印在日志中,登录接口增加防暴力破解,文件系统操作增加路径穿越锁定
|
||||||
**2026.02.10** - 重构任务调度系统,完善并发控制,优化文件树交互体验,支持任务执行实时日志流
|
**2026.02.10** - 重构任务调度系统,完善并发控制,优化文件树交互体验,支持任务执行实时日志流
|
||||||
**2026.02.06** - 整理 Docker 目录结构,增加 Alpine 及 Debian 13 (Trixie) 镜像支持
|
**2026.02.06** - 整理 Docker 目录结构,增加 Alpine 及 Debian 13 (Trixie) 镜像支持
|
||||||
|
|
||||||
@@ -501,9 +502,9 @@ nginx -t && nginx -s reload
|
|||||||
|
|
||||||
启动后访问:http://localhost:8052
|
启动后访问:http://localhost:8052
|
||||||
|
|
||||||
**默认账号:** `admin` / `123456`
|
**默认账号:** 用户名 `admin`,密码见启动日志(首次启动会自动生成 12 位随机密码并打印在日志中)
|
||||||
|
|
||||||
> 首次登录后请立即修改默认密码
|
> **注意**:出于安全性考虑,系统不再使用固定默认密码。请在容器启动日志中搜索 `管理员账号创建成功` 找到您的随机密码,并登录后及时修改。
|
||||||
|
|
||||||
### 数据目录
|
### 数据目录
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/engigu/baihu-panel/internal/constant"
|
"github.com/engigu/baihu-panel/internal/constant"
|
||||||
"github.com/engigu/baihu-panel/internal/middleware"
|
"github.com/engigu/baihu-panel/internal/middleware"
|
||||||
@@ -17,6 +19,13 @@ type AuthController struct {
|
|||||||
loginLogService *services.LoginLogService
|
loginLogService *services.LoginLogService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type loginAttempt struct {
|
||||||
|
Count int
|
||||||
|
LastAttempt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginAttempts sync.Map
|
||||||
|
|
||||||
func NewAuthController(userService *services.UserService, settingsService *services.SettingsService, loginLogService *services.LoginLogService) *AuthController {
|
func NewAuthController(userService *services.UserService, settingsService *services.SettingsService, loginLogService *services.LoginLogService) *AuthController {
|
||||||
return &AuthController{
|
return &AuthController{
|
||||||
userService: userService,
|
userService: userService,
|
||||||
@@ -39,14 +48,37 @@ func (ac *AuthController) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 暴力破解防御
|
||||||
|
if val, ok := loginAttempts.Load(ip); ok {
|
||||||
|
attempt := val.(*loginAttempt)
|
||||||
|
if attempt.Count >= 5 && time.Since(attempt.LastAttempt) < time.Minute {
|
||||||
|
ac.loginLogService.Create(req.Username, ip, userAgent, "failed", "尝试次数过多,请一分钟后再试")
|
||||||
|
utils.TooManyRequests(c, "尝试次数过多,请一分钟后再试")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 如果距离上次尝试已超过一分钟,重置计数
|
||||||
|
if time.Since(attempt.LastAttempt) >= time.Minute {
|
||||||
|
loginAttempts.Delete(ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user := ac.userService.GetUserByUsername(req.Username)
|
user := ac.userService.GetUserByUsername(req.Username)
|
||||||
if user == nil || !ac.userService.ValidatePassword(user, req.Password) {
|
if user == nil || !ac.userService.ValidatePassword(user, req.Password) {
|
||||||
|
// 记录失败尝试
|
||||||
|
val, _ := loginAttempts.LoadOrStore(ip, &loginAttempt{Count: 0, LastAttempt: time.Now()})
|
||||||
|
attempt := val.(*loginAttempt)
|
||||||
|
attempt.Count++
|
||||||
|
attempt.LastAttempt = time.Now()
|
||||||
|
|
||||||
// 记录登录失败日志
|
// 记录登录失败日志
|
||||||
ac.loginLogService.Create(req.Username, ip, userAgent, "failed", "用户名或密码错误")
|
ac.loginLogService.Create(req.Username, ip, userAgent, "failed", "用户名或密码错误")
|
||||||
utils.Unauthorized(c, "用户名或密码错误")
|
utils.Unauthorized(c, "用户名或密码错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 登录成功,清除尝试记录
|
||||||
|
loginAttempts.Delete(ip)
|
||||||
|
|
||||||
// 获取 cookie 过期天数
|
// 获取 cookie 过期天数
|
||||||
expireDays := 7
|
expireDays := 7
|
||||||
if days := ac.settingsService.Get(constant.SectionSite, constant.KeyCookieDays); days != "" {
|
if days := ac.settingsService.Get(constant.SectionSite, constant.KeyCookieDays); days != "" {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/engigu/baihu-panel/internal/logger"
|
"github.com/engigu/baihu-panel/internal/logger"
|
||||||
|
"github.com/engigu/baihu-panel/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InitService struct {
|
type InitService struct {
|
||||||
@@ -40,6 +41,12 @@ func (s *InitService) initializeAdmin(userService *UserService) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userService.CreateUser("admin", "123456", "admin@local", "admin")
|
password := utils.RandomString(12)
|
||||||
logger.Info("管理员账号创建成功: admin / 123456")
|
userService.CreateUser("admin", password, "admin@local", "admin")
|
||||||
|
logger.Infof("--------------------------------------------------")
|
||||||
|
logger.Infof("管理员账号创建成功:")
|
||||||
|
logger.Infof("用户名: admin")
|
||||||
|
logger.Infof("密 码: %s", password)
|
||||||
|
logger.Infof("请妥善保管您的密码,并登录后及时修改。")
|
||||||
|
logger.Infof("--------------------------------------------------")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
|
||||||
|
// RandomString 生成指定长度的随机字符串
|
||||||
|
func RandomString(n int) string {
|
||||||
|
b := make([]byte, n)
|
||||||
|
for i := range b {
|
||||||
|
num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
|
||||||
|
b[i] = charset[num.Int64()]
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
@@ -50,6 +50,10 @@ func NotFound(c *gin.Context, msg string) {
|
|||||||
Error(c, 404, msg)
|
Error(c, 404, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TooManyRequests(c *gin.Context, msg string) {
|
||||||
|
Error(c, 429, msg)
|
||||||
|
}
|
||||||
|
|
||||||
func ServerError(c *gin.Context, msg string) {
|
func ServerError(c *gin.Context, msg string) {
|
||||||
Error(c, 500, msg)
|
Error(c, 500, msg)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user