update: User transmission interface encryption

This commit is contained in:
EUForest 2025-10-12 19:10:52 +08:00
parent 3efa68d3ff
commit 8c776cdbac
13 changed files with 87 additions and 29 deletions

View File

@ -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 {

View File

@ -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)
}

View File

@ -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))

View File

@ -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()))

View File

@ -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()))

View File

@ -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()))

View File

@ -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()))

View File

@ -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()))

View File

@ -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()))

View File

@ -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

View File

@ -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是否存在数据存在就尝试解密并设置回去

View File

@ -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 {

View File

@ -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"`
}