mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 00:26:37 +08:00
refactor(util): move response helper to common/response and session logic to oauth
- Relocated generic HTTP response helpers (Response, OK, Err, etc.) from internal/util/ to a dedicated internal/common/response/ package. - Renamed ResponseAny to Any to resolve revive stuttering warnings. - Moved session building options and cookie headers logic from internal/util/ to internal/apps/oauth/. - Removed all direct imports of Gin/Sessions/HTTP frameworks from internal/util/ to keep general utilities 100% pure. - Regenerated Swagger API documentation via make swagger. - All tests and make code-check compile and pass with 0 issues.
This commit is contained in:
@@ -3,8 +3,7 @@
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
import ("context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -20,6 +19,7 @@ import (
|
||||
"github.com/Rain-kl/Wavelet/pkg/logger"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/Rain-kl/Wavelet/internal/common/response"
|
||||
)
|
||||
|
||||
type loginRequest struct {
|
||||
@@ -83,14 +83,14 @@ func setLoginSession(ctx context.Context, c *gin.Context, user *model.User) erro
|
||||
isSessionCookie = true
|
||||
}
|
||||
}
|
||||
session.Options(util.GetSessionOptions(maxAge))
|
||||
session.Options(oauth.GetSessionOptions(maxAge))
|
||||
|
||||
if err := session.Save(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isSessionCookie {
|
||||
util.StripCookieMaxAgeAndExpires(c.Writer.Header(), config.Config.App.SessionCookieName)
|
||||
oauth.StripCookieMaxAgeAndExpires(c.Writer.Header(), config.Config.App.SessionCookieName)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -103,23 +103,23 @@ func setLoginSession(ctx context.Context, c *gin.Context, user *model.User) erro
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body user.loginRequest true "登录请求参数"
|
||||
// @Success 200 {object} util.ResponseAny{data=oauth.BasicUserInfo} "登录成功,返回用户信息"
|
||||
// @Failure 400 {object} util.ResponseAny "用户名或密码错误、帐号已禁用等"
|
||||
// @Failure 500 {object} util.ResponseAny "服务内部错误"
|
||||
// @Success 200 {object} response.Any{data=oauth.BasicUserInfo} "登录成功,返回用户信息"
|
||||
// @Failure 400 {object} response.Any "用户名或密码错误、帐号已禁用等"
|
||||
// @Failure 500 {object} response.Any "服务内部错误"
|
||||
// @Router /api/v1/user/login [post]
|
||||
func Login(c *gin.Context) {
|
||||
if !isPasswordLoginEnabled() {
|
||||
c.JSON(http.StatusOK, util.Err(errPasswordLoginDisabled))
|
||||
c.JSON(http.StatusOK, response.Err(errPasswordLoginDisabled))
|
||||
return
|
||||
}
|
||||
var req loginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
req.Username = strings.TrimSpace(req.Username)
|
||||
if req.Username == "" || req.Password == "" {
|
||||
c.JSON(http.StatusOK, util.Err(errInvalidParams))
|
||||
c.JSON(http.StatusOK, response.Err(errInvalidParams))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,12 +127,12 @@ func Login(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
if err := db.DB(ctx).Where("username = ? OR email = ?", req.Username, req.Username).First(&user).Error; err != nil {
|
||||
logger.WarnF(ctx, "[LoginAudit] failed login attempt (username not found) for input: %s, IP: %s", req.Username, c.ClientIP())
|
||||
c.JSON(http.StatusOK, util.Err(errUsernameOrPasswordWrong))
|
||||
c.JSON(http.StatusOK, response.Err(errUsernameOrPasswordWrong))
|
||||
return
|
||||
}
|
||||
if !user.IsActive {
|
||||
logger.WarnF(ctx, "[LoginAudit] banned user login attempt for username: %s, ID: %d, IP: %s", user.Username, user.ID, c.ClientIP())
|
||||
c.JSON(http.StatusOK, util.Err(common.BannedAccount))
|
||||
c.JSON(http.StatusOK, response.Err(common.BannedAccount))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ func Login(c *gin.Context) {
|
||||
|
||||
if !user.CheckPassword(req.Password) {
|
||||
logger.WarnF(ctx, "[LoginAudit] failed login attempt (incorrect password) for username: %s, ID: %d, IP: %s", user.Username, user.ID, c.ClientIP())
|
||||
c.JSON(http.StatusOK, util.Err(errUsernameOrPasswordWrong))
|
||||
c.JSON(http.StatusOK, response.Err(errUsernameOrPasswordWrong))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -162,11 +162,11 @@ func Login(c *gin.Context) {
|
||||
|
||||
user.LastLoginAt = time.Now()
|
||||
if err := db.DB(ctx).Model(&user).Update("last_login_at", user.LastLoginAt).Error; err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
if err := setLoginSession(ctx, c, &user); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(errSaveSessionFailed))
|
||||
c.JSON(http.StatusOK, response.Err(errSaveSessionFailed))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ func Login(c *gin.Context) {
|
||||
|
||||
custom_events.TriggerAdminLoginEvent(ctx, &user, c.ClientIP())
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(oauth.BuildBasicUserInfo(&user, needChangePassword)))
|
||||
c.JSON(http.StatusOK, response.OK(oauth.BuildBasicUserInfo(&user, needChangePassword)))
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
@@ -184,19 +184,19 @@ func Login(c *gin.Context) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body user.registerRequest true "注册请求参数"
|
||||
// @Success 200 {object} util.ResponseAny{data=oauth.BasicUserInfo} "注册并登录成功,返回用户信息"
|
||||
// @Failure 400 {object} util.ResponseAny "参数错误、用户名已存在或注册已关闭"
|
||||
// @Failure 500 {object} util.ResponseAny "服务内部错误"
|
||||
// @Success 200 {object} response.Any{data=oauth.BasicUserInfo} "注册并登录成功,返回用户信息"
|
||||
// @Failure 400 {object} response.Any "参数错误、用户名已存在或注册已关闭"
|
||||
// @Failure 500 {object} response.Any "服务内部错误"
|
||||
// @Router /api/v1/user/register [post]
|
||||
func Register(c *gin.Context) {
|
||||
if !isRegistrationEnabled() || !isPasswordRegisterEnabled() {
|
||||
c.JSON(http.StatusOK, util.Err(errRegistrationDisabled))
|
||||
c.JSON(http.StatusOK, response.Err(errRegistrationDisabled))
|
||||
return
|
||||
}
|
||||
|
||||
var req registerRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -208,15 +208,15 @@ func Register(c *gin.Context) {
|
||||
req.Code = strings.TrimSpace(req.Code)
|
||||
|
||||
if req.Username == "" || req.Password == "" {
|
||||
c.JSON(http.StatusOK, util.Err(errInvalidParams))
|
||||
c.JSON(http.StatusOK, response.Err(errInvalidParams))
|
||||
return
|
||||
}
|
||||
if req.Email == "" {
|
||||
c.JSON(http.StatusOK, util.Err(errEmailRequired))
|
||||
c.JSON(http.StatusOK, response.Err(errEmailRequired))
|
||||
return
|
||||
}
|
||||
if len(req.Password) < minPasswordLength {
|
||||
c.JSON(http.StatusOK, util.Err(errPasswordTooShort))
|
||||
c.JSON(http.StatusOK, response.Err(errPasswordTooShort))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ func Register(c *gin.Context) {
|
||||
|
||||
// 邮箱注册验证校验
|
||||
if err := validateRegisterEmailVerification(ctx, &req); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -245,21 +245,21 @@ func Register(c *gin.Context) {
|
||||
user.Nickname = req.Username
|
||||
}
|
||||
if err := user.SetEncryptedPassword(req.Password); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if err := user.RegisterUser(ctx, db.DB(ctx)); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if err := setLoginSession(ctx, c, &user); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(errSaveSessionFailed))
|
||||
c.JSON(http.StatusOK, response.Err(errSaveSessionFailed))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(oauth.BuildBasicUserInfo(&user, false)))
|
||||
c.JSON(http.StatusOK, response.OK(oauth.BuildBasicUserInfo(&user, false)))
|
||||
}
|
||||
|
||||
// Logout 用户退出登录
|
||||
@@ -268,8 +268,8 @@ func Register(c *gin.Context) {
|
||||
// @Tags user
|
||||
// @Produce json
|
||||
// @Security SessionCookie
|
||||
// @Success 200 {object} util.ResponseAny{data=string} "退出成功"
|
||||
// @Failure 500 {object} util.ResponseAny "Session 清除失败"
|
||||
// @Success 200 {object} response.Any{data=string} "退出成功"
|
||||
// @Failure 500 {object} response.Any "Session 清除失败"
|
||||
// @Router /api/v1/user/logout [get]
|
||||
func Logout(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
@@ -278,13 +278,13 @@ func Logout(c *gin.Context) {
|
||||
if userID != nil {
|
||||
logger.InfoF(c.Request.Context(), "[LoginAudit] user logged out: %v, ID: %v, IP: %s", username, userID, c.ClientIP())
|
||||
}
|
||||
session.Options(util.GetSessionOptions(-1))
|
||||
session.Options(oauth.GetSessionOptions(-1))
|
||||
session.Clear()
|
||||
if err := session.Save(); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, util.OK(""))
|
||||
c.JSON(http.StatusOK, response.OK(""))
|
||||
}
|
||||
|
||||
type changePasswordRequest struct {
|
||||
@@ -299,14 +299,14 @@ type changePasswordRequest struct {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body user.changePasswordRequest true "修改密码请求参数"
|
||||
// @Success 200 {object} util.ResponseAny{data=string} "修改密码成功"
|
||||
// @Failure 400 {object} util.ResponseAny "原密码错误或新密码不符合要求"
|
||||
// @Failure 401 {object} util.ResponseAny "请先登录"
|
||||
// @Success 200 {object} response.Any{data=string} "修改密码成功"
|
||||
// @Failure 400 {object} response.Any "原密码错误或新密码不符合要求"
|
||||
// @Failure 401 {object} response.Any "请先登录"
|
||||
// @Router /api/v1/user/change-password [post]
|
||||
func ChangePassword(c *gin.Context) {
|
||||
var req changePasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
c.JSON(http.StatusBadRequest, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -314,47 +314,47 @@ func ChangePassword(c *gin.Context) {
|
||||
req.NewPassword = strings.TrimSpace(req.NewPassword)
|
||||
|
||||
if req.OldPassword == "" || req.NewPassword == "" {
|
||||
c.JSON(http.StatusOK, util.Err(errInvalidParams))
|
||||
c.JSON(http.StatusOK, response.Err(errInvalidParams))
|
||||
return
|
||||
}
|
||||
if len(req.NewPassword) < minPasswordLength {
|
||||
c.JSON(http.StatusOK, util.Err(errNewPasswordTooShort))
|
||||
c.JSON(http.StatusOK, response.Err(errNewPasswordTooShort))
|
||||
return
|
||||
}
|
||||
|
||||
userObj, _ := util.GetFromContext[*model.User](c, oauth.UserObjKey)
|
||||
if userObj == nil {
|
||||
c.JSON(http.StatusUnauthorized, util.Err(errLoginRequired))
|
||||
c.JSON(http.StatusUnauthorized, response.Err(errLoginRequired))
|
||||
return
|
||||
}
|
||||
|
||||
ctx := c.Request.Context()
|
||||
var dbUser model.User
|
||||
if err := db.DB(ctx).Where("id = ?", userObj.ID).First(&dbUser).Error; err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(errUserNotFound))
|
||||
c.JSON(http.StatusOK, response.Err(errUserNotFound))
|
||||
return
|
||||
}
|
||||
|
||||
// 校验旧密码
|
||||
if !dbUser.CheckPassword(req.OldPassword) {
|
||||
c.JSON(http.StatusOK, util.Err(errOldPasswordIncorrect))
|
||||
c.JSON(http.StatusOK, response.Err(errOldPasswordIncorrect))
|
||||
return
|
||||
}
|
||||
|
||||
// 加密并更新为新密码
|
||||
if err := dbUser.SetEncryptedPassword(req.NewPassword); err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(errPasswordEncryptFailed))
|
||||
c.JSON(http.StatusOK, response.Err(errPasswordEncryptFailed))
|
||||
return
|
||||
}
|
||||
|
||||
if err := db.DB(ctx).Model(&dbUser).Update("password", dbUser.Password).Error; err != nil {
|
||||
c.JSON(http.StatusOK, util.Err(err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 吊销该用户所有的 Access Token
|
||||
if err := db.DB(ctx).Where("user_id = ?", dbUser.ID).Delete(&model.AccessToken{}).Error; err != nil {
|
||||
c.JSON(http.StatusOK, util.Err("吊销 Access Token 失败: "+err.Error()))
|
||||
c.JSON(http.StatusOK, response.Err("吊销 Access Token 失败: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -363,5 +363,5 @@ func ChangePassword(c *gin.Context) {
|
||||
session.Clear()
|
||||
_ = session.Save()
|
||||
|
||||
c.JSON(http.StatusOK, util.OK("密码修改成功"))
|
||||
c.JSON(http.StatusOK, response.OK("密码修改成功"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user