diff --git a/apis/auth/auth.api b/apis/auth/auth.api index 68fe700..154c878 100644 --- a/apis/auth/auth.api +++ b/apis/auth/auth.api @@ -16,6 +16,7 @@ type ( Password string `json:"password" validate:"required"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } // Check user is exist request @@ -35,6 +36,7 @@ type ( Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } // User login response @@ -45,6 +47,7 @@ type ( Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } LoginResponse { @@ -70,6 +73,7 @@ type ( Password string `json:"password"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } // Check user is exist request @@ -91,6 +95,7 @@ type ( Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type,optional"` CfToken string `json:"cf_token,optional"` } // User login response @@ -102,6 +107,7 @@ type ( Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type,optional"` CfToken string `json:"cf_token,optional"` } AppleLoginCallbackRequest { diff --git a/apis/public/user.api b/apis/public/user.api index 2547e5b..1686b32 100644 --- a/apis/public/user.api +++ b/apis/public/user.api @@ -97,6 +97,15 @@ type ( Email string `json:"email" validate:"required"` Code string `json:"code" validate:"required"` } + + GetDeviceListResponse { + List []UserDevice `json:"list"` + Total int64 `json:"total"` + } + + UnbindDeviceRequest { + Id int64 `json:"id" validate:"required"` + } ) @server ( @@ -192,5 +201,13 @@ service ppanel { @doc "Update Bind Email" @handler UpdateBindEmail put /bind_email (UpdateBindEmailRequest) + + @doc "Get Device List" + @handler GetDeviceList + get /devices returns (GetDeviceListResponse) + + @doc "Unbind Device" + @handler UnbindDevice + put /unbind_device (UnbindDeviceRequest) } diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 7109585..c6832ec 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -792,6 +792,9 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Query User Commission Log publicUserGroupRouter.GET("/commission_log", publicUser.QueryUserCommissionLogHandler(serverCtx)) + // Get Device List + publicUserGroupRouter.GET("/devices", publicUser.GetDeviceListHandler(serverCtx)) + // Query User Info publicUserGroupRouter.GET("/info", publicUser.QueryUserInfoHandler(serverCtx)) @@ -816,6 +819,9 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Reset User Subscribe Token publicUserGroupRouter.PUT("/subscribe_token", publicUser.ResetUserSubscribeTokenHandler(serverCtx)) + // Unbind Device + publicUserGroupRouter.PUT("/unbind_device", publicUser.UnbindDeviceHandler(serverCtx)) + // Unbind OAuth publicUserGroupRouter.POST("/unbind_oauth", publicUser.UnbindOAuthHandler(serverCtx)) diff --git a/internal/logic/auth/resetPasswordLogic.go b/internal/logic/auth/resetPasswordLogic.go index 40a1ba4..c4e2ece 100644 --- a/internal/logic/auth/resetPasswordLogic.go +++ b/internal/logic/auth/resetPasswordLogic.go @@ -108,8 +108,6 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update user info failed: %v", err.Error()) } - loginType := "pc" - // Bind device to user if identifier is provided if req.Identifier != "" { bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx) @@ -121,9 +119,10 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res ) // Don't fail register if device binding fails, just log the error } - loginType = "mobile" } - + if l.ctx.Value(constant.LoginType) != nil { + req.LoginType = l.ctx.Value(constant.LoginType).(string) + } // Generate session id sessionId := uuidx.NewUUID().String() // Generate token @@ -133,7 +132,7 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res l.svcCtx.Config.JwtAuth.AccessExpire, jwt.WithOption("UserId", userInfo.Id), jwt.WithOption("SessionId", sessionId), - jwt.WithOption("LoginType", loginType), + jwt.WithOption("LoginType", req.LoginType), ) if err != nil { l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) diff --git a/internal/logic/auth/telephoneLoginLogic.go b/internal/logic/auth/telephoneLoginLogic.go index 4b630b9..737157f 100644 --- a/internal/logic/auth/telephoneLoginLogic.go +++ b/internal/logic/auth/telephoneLoginLogic.go @@ -124,7 +124,6 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r l.svcCtx.Redis.Del(l.ctx, cacheKey) } - loginType := "pc" // Bind device to user if identifier is provided if req.Identifier != "" { bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx) @@ -136,7 +135,10 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r ) // Don't fail login if device binding fails, just log the error } - loginType = "device" + } + + if l.ctx.Value(constant.LoginType) != nil { + req.LoginType = l.ctx.Value(constant.LoginType).(string) } // Generate session id @@ -148,7 +150,7 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r l.svcCtx.Config.JwtAuth.AccessExpire, jwt.WithOption("UserId", userInfo.Id), jwt.WithOption("SessionId", sessionId), - jwt.WithOption("LoginType", loginType), + jwt.WithOption("LoginType", req.LoginType), ) if err != nil { l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) diff --git a/internal/logic/auth/telephoneResetPasswordLogic.go b/internal/logic/auth/telephoneResetPasswordLogic.go index 7f5d928..f119c55 100644 --- a/internal/logic/auth/telephoneResetPasswordLogic.go +++ b/internal/logic/auth/telephoneResetPasswordLogic.go @@ -83,8 +83,6 @@ func (l *TelephoneResetPasswordLogic) TelephoneResetPassword(req *types.Telephon return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "update user password failed: %v", err.Error()) } - loginType := "pc" - // Bind device to user if identifier is provided if req.Identifier != "" { bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx) @@ -96,9 +94,10 @@ func (l *TelephoneResetPasswordLogic) TelephoneResetPassword(req *types.Telephon ) // Don't fail register if device binding fails, just log the error } - loginType = "mobile" } - + if l.ctx.Value(constant.LoginType) != nil { + req.LoginType = l.ctx.Value(constant.LoginType).(string) + } // Generate session id sessionId := uuidx.NewUUID().String() // Generate token @@ -108,7 +107,7 @@ func (l *TelephoneResetPasswordLogic) TelephoneResetPassword(req *types.Telephon l.svcCtx.Config.JwtAuth.AccessExpire, jwt.WithOption("UserId", userInfo.Id), jwt.WithOption("SessionId", sessionId), - jwt.WithOption("LoginType", loginType), + jwt.WithOption("LoginType", req.LoginType), ) if err != nil { l.Errorw("[UserLogin] token generate error", logger.Field("error", err.Error())) diff --git a/internal/logic/auth/telephoneUserRegisterLogic.go b/internal/logic/auth/telephoneUserRegisterLogic.go index 1952990..aa2dde9 100644 --- a/internal/logic/auth/telephoneUserRegisterLogic.go +++ b/internal/logic/auth/telephoneUserRegisterLogic.go @@ -139,8 +139,6 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR return nil }) - loginType := "pc" - // Bind device to user if identifier is provided if req.Identifier != "" { bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx) @@ -152,9 +150,10 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR ) // Don't fail register if device binding fails, just log the error } - loginType = "mobile" } - + if l.ctx.Value(constant.LoginType) != nil { + req.LoginType = l.ctx.Value(constant.LoginType).(string) + } // Generate session id sessionId := uuidx.NewUUID().String() // Generate token @@ -164,7 +163,7 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR l.svcCtx.Config.JwtAuth.AccessExpire, jwt.WithOption("UserId", userInfo.Id), jwt.WithOption("SessionId", sessionId), - jwt.WithOption("LoginType", loginType), + jwt.WithOption("LoginType", req.LoginType), ) if err != nil { l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) diff --git a/internal/logic/auth/userLoginLogic.go b/internal/logic/auth/userLoginLogic.go index 6c53f36..3062e63 100644 --- a/internal/logic/auth/userLoginLogic.go +++ b/internal/logic/auth/userLoginLogic.go @@ -6,6 +6,7 @@ import ( "time" "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/internal/config" @@ -79,7 +80,6 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log if !tool.VerifyPassWord(req.Password, userInfo.Password) { return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") } - loginType := "pc" // Bind device to user if identifier is provided if req.Identifier != "" { @@ -92,9 +92,10 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log ) // Don't fail login if device binding fails, just log the error } - loginType = "device" } - + if l.ctx.Value(constant.LoginType) != nil { + req.LoginType = l.ctx.Value(constant.LoginType).(string) + } // Generate session id sessionId := uuidx.NewUUID().String() // Generate token @@ -104,7 +105,7 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log l.svcCtx.Config.JwtAuth.AccessExpire, jwt.WithOption("UserId", userInfo.Id), jwt.WithOption("SessionId", sessionId), - jwt.WithOption("LoginType", loginType), + jwt.WithOption("LoginType", req.LoginType), ) if err != nil { l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) diff --git a/internal/logic/auth/userRegisterLogic.go b/internal/logic/auth/userRegisterLogic.go index 34b2646..0b9da43 100644 --- a/internal/logic/auth/userRegisterLogic.go +++ b/internal/logic/auth/userRegisterLogic.go @@ -125,7 +125,6 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp * } return nil }) - loginType := "pc" // Bind device to user if identifier is provided if req.Identifier != "" { bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx) @@ -137,9 +136,10 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp * ) // Don't fail register if device binding fails, just log the error } - loginType = "device" } - + if l.ctx.Value(constant.LoginType) != nil { + req.LoginType = l.ctx.Value(constant.LoginType).(string) + } // Generate session id sessionId := uuidx.NewUUID().String() // Generate token @@ -149,7 +149,7 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp * l.svcCtx.Config.JwtAuth.AccessExpire, jwt.WithOption("UserId", userInfo.Id), jwt.WithOption("SessionId", sessionId), - jwt.WithOption("LoginType", loginType), + jwt.WithOption("LoginType", req.LoginType), ) if err != nil { l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) diff --git a/internal/middleware/authMiddleware.go b/internal/middleware/authMiddleware.go index 7c86865..fbf3758 100644 --- a/internal/middleware/authMiddleware.go +++ b/internal/middleware/authMiddleware.go @@ -41,7 +41,10 @@ func AuthMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { return } - loginType := claims["LoginType"].(string) + loginType := "" + if claims["LoginType"] != nil { + loginType = claims["LoginType"].(string) + } // get user id from token userId := int64(claims["UserId"].(float64)) // get session id from token diff --git a/internal/middleware/deviceMiddleware.go b/internal/middleware/deviceMiddleware.go index a2d6805..501d4d0 100644 --- a/internal/middleware/deviceMiddleware.go +++ b/internal/middleware/deviceMiddleware.go @@ -3,6 +3,7 @@ package middleware import ( "bufio" "bytes" + "context" "encoding/json" "fmt" "io" @@ -37,6 +38,8 @@ func DeviceMiddleware(srvCtx *svc.ServiceContext) func(c *gin.Context) { return } + c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), constant.LoginType, loginType)) + if !srvCtx.Config.Device.Enable || srvCtx.Config.Device.SecuritySecret == "" { c.Next() return @@ -123,8 +126,6 @@ func (rw *ResponseWriter) Decrypt() bool { rw.c.Request.URL.RawQuery = query.Encode() } } - } else { - return false } //判断body是否存在数据,存在就尝试解密,并设置回去 diff --git a/internal/model/user/device.go b/internal/model/user/device.go index 4d3edd1..f823991 100644 --- a/internal/model/user/device.go +++ b/internal/model/user/device.go @@ -46,6 +46,16 @@ func (m *customUserModel) QueryDevicePageList(ctx context.Context, userId, subsc return list, total, err } +// QueryDeviceList returns a list of records that meet the conditions. +func (m *customUserModel) QueryDeviceList(ctx context.Context, userId int64) ([]*Device, int64, error) { + var list []*Device + var total int64 + err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { + return conn.Model(&Device{}).Where("`user_id` = ? and `subscribe_id` = ?", userId).Count(&total).Find(&list).Error + }) + return list, total, err +} + func (m *customUserModel) UpdateDevice(ctx context.Context, data *Device, tx ...*gorm.DB) error { old, err := m.FindOneDevice(ctx, data.Id) if err != nil { diff --git a/internal/types/types.go b/internal/types/types.go index 14e3120..89d404c 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -817,6 +817,11 @@ type GetDetailRequest struct { Id int64 `form:"id" validate:"required"` } +type GetDeviceListResponse struct { + List []UserDevice `json:"list"` + Total int64 `json:"total"` +} + type GetDocumentDetailRequest struct { Id int64 `json:"id" validate:"required"` } @@ -1758,6 +1763,7 @@ type ResetPasswordRequest struct { Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } @@ -2113,6 +2119,7 @@ type TelephoneLoginRequest struct { Password string `json:"password"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } @@ -2125,6 +2132,7 @@ type TelephoneRegisterRequest struct { Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type,optional"` CfToken string `json:"cf_token,optional"` } @@ -2136,6 +2144,7 @@ type TelephoneResetPasswordRequest struct { Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type,optional"` CfToken string `json:"cf_token,optional"` } @@ -2230,6 +2239,10 @@ type Tuic struct { SecurityConfig SecurityConfig `json:"security_config"` } +type UnbindDeviceRequest struct { + Id int64 `json:"id" validate:"required"` +} + type UnbindOAuthRequest struct { Method string `json:"method"` } @@ -2514,6 +2527,7 @@ type UserLoginRequest struct { Password string `json:"password" validate:"required"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` } @@ -2525,6 +2539,7 @@ type UserRegisterRequest struct { Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` CfToken string `json:"cf_token,optional"` }