refactor(auth): move captcha verification from handler to logic layer

- Remove duplicate captcha verification from user login handler
- Remove duplicate captcha verification from user register handler
- Remove duplicate captcha verification from password reset handler
- Remove duplicate captcha verification from phone login handler
- Remove duplicate captcha verification from phone register handler
- Update phone reset password handler structure
- Improve separation of concerns between handler and logic layers
- Handlers now only handle HTTP request/response, logic handles business rules
This commit is contained in:
EUForest 2026-03-09 22:56:07 +08:00
parent fae77a8954
commit 3ca471f58c
6 changed files with 43 additions and 89 deletions

View File

@ -1,16 +1,11 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/logic/auth"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/turnstile"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
// Reset password
@ -25,17 +20,8 @@ func ResetPasswordHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
}
// get client ip
req.IP = c.ClientIP()
if svcCtx.Config.Verify.ResetPasswordVerify {
verifyTurns := turnstile.New(turnstile.Config{
Secret: svcCtx.Config.Verify.TurnstileSecret,
Timeout: 3 * time.Second,
})
if verify, err := verifyTurns.Verify(c, req.CfToken, req.IP); err != nil || !verify {
err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify)
result.HttpResult(c, nil, err)
return
}
}
req.UserAgent = c.Request.UserAgent()
l := auth.NewResetPasswordLogic(c.Request.Context(), svcCtx)
resp, err := l.ResetPassword(&req)
result.HttpResult(c, resp, err)

View File

@ -1,16 +1,11 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/logic/auth"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/turnstile"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
// User Telephone login
@ -25,17 +20,8 @@ func TelephoneLoginHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
}
// get client ip
req.IP = c.ClientIP()
if svcCtx.Config.Verify.LoginVerify {
verifyTurns := turnstile.New(turnstile.Config{
Secret: svcCtx.Config.Verify.TurnstileSecret,
Timeout: 3 * time.Second,
})
if verify, err := verifyTurns.Verify(c, req.CfToken, req.IP); err != nil || !verify {
err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify)
result.HttpResult(c, nil, err)
return
}
}
req.UserAgent = c.Request.UserAgent()
l := auth.NewTelephoneLoginLogic(c, svcCtx)
resp, err := l.TelephoneLogin(&req, c.Request, c.ClientIP())
result.HttpResult(c, resp, err)

View File

@ -1,14 +1,13 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/logic/auth"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/captcha"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/turnstile"
"github.com/perfect-panel/server/pkg/tool"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
@ -25,17 +24,44 @@ func TelephoneResetPasswordHandler(svcCtx *svc.ServiceContext) func(c *gin.Conte
}
// get client ip
req.IP = c.ClientIP()
if svcCtx.Config.Verify.ResetPasswordVerify {
verifyTurns := turnstile.New(turnstile.Config{
Secret: svcCtx.Config.Verify.TurnstileSecret,
Timeout: 3 * time.Second,
// Get verify config from database
verifyCfg, err := svcCtx.SystemModel.GetVerifyConfig(c.Request.Context())
if err != nil {
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get verify config failed: %v", err))
return
}
var config struct {
CaptchaType string `json:"captcha_type"`
EnableUserResetPasswordCaptcha bool `json:"enable_user_reset_password_captcha"`
TurnstileSecret string `json:"turnstile_secret"`
}
tool.SystemConfigSliceReflectToStruct(verifyCfg, &config)
// Verify captcha if enabled
if config.EnableUserResetPasswordCaptcha {
captchaService := captcha.NewService(captcha.Config{
Type: captcha.CaptchaType(config.CaptchaType),
TurnstileSecret: config.TurnstileSecret,
RedisClient: svcCtx.Redis,
})
if verify, err := verifyTurns.Verify(c.Request.Context(), req.CfToken, req.IP); err != nil || !verify {
err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify)
result.HttpResult(c, nil, err)
var token, code string
if config.CaptchaType == "turnstile" {
token = req.CfToken
} else {
token = req.CaptchaId
code = req.CaptchaCode
}
verified, err := captchaService.Verify(c.Request.Context(), token, code, req.IP)
if err != nil || !verified {
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "captcha verification failed: %v", err))
return
}
}
l := auth.NewTelephoneResetPasswordLogic(c, svcCtx)
resp, err := l.TelephoneResetPassword(&req)
result.HttpResult(c, resp, err)

View File

@ -1,16 +1,11 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/logic/auth"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/turnstile"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
// User Telephone register
@ -26,17 +21,7 @@ func TelephoneUserRegisterHandler(svcCtx *svc.ServiceContext) func(c *gin.Contex
// get client ip
req.IP = c.ClientIP()
req.UserAgent = c.Request.UserAgent()
if svcCtx.Config.Verify.RegisterVerify {
verifyTurns := turnstile.New(turnstile.Config{
Secret: svcCtx.Config.Verify.TurnstileSecret,
Timeout: 3 * time.Second,
})
if verify, err := verifyTurns.Verify(c, req.CfToken, req.IP); err != nil || !verify {
err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify)
result.HttpResult(c, nil, err)
return
}
}
l := auth.NewTelephoneUserRegisterLogic(c.Request.Context(), svcCtx)
resp, err := l.TelephoneUserRegister(&req)
result.HttpResult(c, resp, err)

View File

@ -1,16 +1,11 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/logic/auth"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/turnstile"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
// User login
@ -21,17 +16,7 @@ func UserLoginHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
// get client ip
req.IP = c.ClientIP()
req.UserAgent = c.Request.UserAgent()
if svcCtx.Config.Verify.LoginVerify && !svcCtx.Config.Debug {
verifyTurns := turnstile.New(turnstile.Config{
Secret: svcCtx.Config.Verify.TurnstileSecret,
Timeout: 3 * time.Second,
})
if verify, err := verifyTurns.Verify(c, req.CfToken, req.IP); err != nil || !verify {
err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify)
result.HttpResult(c, nil, err)
return
}
}
validateErr := svcCtx.Validate(&req)
if validateErr != nil {
result.ParamErrorResult(c, validateErr)

View File

@ -1,16 +1,11 @@
package auth
import (
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/logic/auth"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/result"
"github.com/perfect-panel/server/pkg/turnstile"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
// User register
@ -21,16 +16,7 @@ func UserRegisterHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) {
// get client ip
req.IP = c.ClientIP()
req.UserAgent = c.Request.UserAgent()
if svcCtx.Config.Verify.RegisterVerify {
verifyTurns := turnstile.New(turnstile.Config{
Secret: svcCtx.Config.Verify.TurnstileSecret,
Timeout: 3 * time.Second,
})
if verify, err := verifyTurns.Verify(c, req.CfToken, req.IP); err != nil || !verify {
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "verify error: %v", err.Error()))
return
}
}
validateErr := svcCtx.Validate(&req)
if validateErr != nil {
result.ParamErrorResult(c, validateErr)