feat: adjust deploy password and login limit
This commit is contained in:
@@ -2,6 +2,8 @@ package controllers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/middleware"
|
||||
@@ -17,6 +19,13 @@ type AuthController struct {
|
||||
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 {
|
||||
return &AuthController{
|
||||
userService: userService,
|
||||
@@ -39,14 +48,37 @@ func (ac *AuthController) Login(c *gin.Context) {
|
||||
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)
|
||||
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", "用户名或密码错误")
|
||||
utils.Unauthorized(c, "用户名或密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 登录成功,清除尝试记录
|
||||
loginAttempts.Delete(ip)
|
||||
|
||||
// 获取 cookie 过期天数
|
||||
expireDays := 7
|
||||
if days := ac.settingsService.Get(constant.SectionSite, constant.KeyCookieDays); days != "" {
|
||||
|
||||
@@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"github.com/engigu/baihu-panel/internal/logger"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
)
|
||||
|
||||
type InitService struct {
|
||||
@@ -40,6 +41,12 @@ func (s *InitService) initializeAdmin(userService *UserService) {
|
||||
return
|
||||
}
|
||||
|
||||
userService.CreateUser("admin", "123456", "admin@local", "admin")
|
||||
logger.Info("管理员账号创建成功: admin / 123456")
|
||||
password := utils.RandomString(12)
|
||||
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)
|
||||
}
|
||||
|
||||
func TooManyRequests(c *gin.Context, msg string) {
|
||||
Error(c, 429, msg)
|
||||
}
|
||||
|
||||
func ServerError(c *gin.Context, msg string) {
|
||||
Error(c, 500, msg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user