add: User transmission interface encryption
This commit is contained in:
parent
f3bc933a99
commit
46e6a9784d
@ -39,6 +39,7 @@ type (
|
|||||||
}
|
}
|
||||||
// User login response
|
// User login response
|
||||||
ResetPasswordRequest {
|
ResetPasswordRequest {
|
||||||
|
Identifier string `json:"identifier"`
|
||||||
Email string `json:"email" validate:"required"`
|
Email string `json:"email" validate:"required"`
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
Code string `json:"code,optional"`
|
Code string `json:"code,optional"`
|
||||||
@ -94,6 +95,7 @@ type (
|
|||||||
}
|
}
|
||||||
// User login response
|
// User login response
|
||||||
TelephoneResetPasswordRequest {
|
TelephoneResetPasswordRequest {
|
||||||
|
Identifier string `json:"identifier"`
|
||||||
Telephone string `json:"telephone" validate:"required"`
|
Telephone string `json:"telephone" validate:"required"`
|
||||||
TelephoneAreaCode string `json:"telephone_area_code" validate:"required"`
|
TelephoneAreaCode string `json:"telephone_area_code" validate:"required"`
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
@ -122,6 +124,7 @@ type (
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/auth
|
prefix: v1/auth
|
||||||
group: auth
|
group: auth
|
||||||
|
middleware: DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "User login"
|
@doc "User login"
|
||||||
|
|||||||
@ -92,6 +92,7 @@ type (
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/common
|
prefix: v1/common
|
||||||
group: common
|
group: common
|
||||||
|
middleware: DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Get global config"
|
@doc "Get global config"
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import "../types.api"
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/announcement
|
prefix: v1/public/announcement
|
||||||
group: public/announcement
|
group: public/announcement
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Query announcement"
|
@doc "Query announcement"
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import "../types.api"
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/document
|
prefix: v1/public/document
|
||||||
group: public/document
|
group: public/document
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Get document list"
|
@doc "Get document list"
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import "../types.api"
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/order
|
prefix: v1/public/order
|
||||||
group: public/order
|
group: public/order
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Pre create order"
|
@doc "Pre create order"
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import "../types.api"
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/payment
|
prefix: v1/public/payment
|
||||||
group: public/payment
|
group: public/payment
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Get available payment methods"
|
@doc "Get available payment methods"
|
||||||
|
|||||||
@ -70,6 +70,7 @@ type (
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/portal
|
prefix: v1/public/portal
|
||||||
group: public/portal
|
group: public/portal
|
||||||
|
middleware: DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Get available payment methods"
|
@doc "Get available payment methods"
|
||||||
|
|||||||
@ -19,7 +19,7 @@ type (
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/subscribe
|
prefix: v1/public/subscribe
|
||||||
group: public/subscribe
|
group: public/subscribe
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Get subscribe list"
|
@doc "Get subscribe list"
|
||||||
|
|||||||
@ -43,7 +43,7 @@ type (
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/ticket
|
prefix: v1/public/ticket
|
||||||
group: public/ticket
|
group: public/ticket
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Get ticket list"
|
@doc "Get ticket list"
|
||||||
|
|||||||
@ -102,7 +102,7 @@ type (
|
|||||||
@server (
|
@server (
|
||||||
prefix: v1/public/user
|
prefix: v1/public/user
|
||||||
group: public/user
|
group: public/user
|
||||||
middleware: AuthMiddleware
|
middleware: AuthMiddleware,DeviceMiddleware
|
||||||
)
|
)
|
||||||
service ppanel {
|
service ppanel {
|
||||||
@doc "Query User Info"
|
@doc "Query User Info"
|
||||||
|
|||||||
26
initialize/device.go
Normal file
26
initialize/device.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/internal/config"
|
||||||
|
"github.com/perfect-panel/server/internal/model/auth"
|
||||||
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
|
"github.com/perfect-panel/server/pkg/tool"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Device(ctx *svc.ServiceContext) {
|
||||||
|
logger.Debug("device config initialization")
|
||||||
|
method, err := ctx.AuthModel.FindOneByMethod(context.Background(), "device")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
var cfg config.DeviceConfig
|
||||||
|
var deviceConfig auth.DeviceConfig
|
||||||
|
deviceConfig.Unmarshal(method.Config)
|
||||||
|
tool.DeepCopy(&cfg, deviceConfig)
|
||||||
|
cfg.Enable = *method.Enabled
|
||||||
|
ctx.Config.Device = cfg
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ func StartInitSystemConfig(svc *svc.ServiceContext) {
|
|||||||
Site(svc)
|
Site(svc)
|
||||||
Node(svc)
|
Node(svc)
|
||||||
Email(svc)
|
Email(svc)
|
||||||
|
Device(svc)
|
||||||
Invite(svc)
|
Invite(svc)
|
||||||
Verify(svc)
|
Verify(svc)
|
||||||
Subscribe(svc)
|
Subscribe(svc)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/perfect-panel/server/pkg/logger"
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
"github.com/perfect-panel/server/pkg/orm"
|
"github.com/perfect-panel/server/pkg/orm"
|
||||||
)
|
)
|
||||||
@ -20,6 +21,7 @@ type Config struct {
|
|||||||
Node NodeConfig `yaml:"Node"`
|
Node NodeConfig `yaml:"Node"`
|
||||||
Mobile MobileConfig `yaml:"Mobile"`
|
Mobile MobileConfig `yaml:"Mobile"`
|
||||||
Email EmailConfig `yaml:"Email"`
|
Email EmailConfig `yaml:"Email"`
|
||||||
|
Device DeviceConfig `yaml:"device"`
|
||||||
Verify Verify `yaml:"Verify"`
|
Verify Verify `yaml:"Verify"`
|
||||||
VerifyCode VerifyCode `yaml:"VerifyCode"`
|
VerifyCode VerifyCode `yaml:"VerifyCode"`
|
||||||
Register RegisterConfig `yaml:"Register"`
|
Register RegisterConfig `yaml:"Register"`
|
||||||
@ -95,6 +97,14 @@ type MobileConfig struct {
|
|||||||
Whitelist []string `yaml:"whitelist"`
|
Whitelist []string `yaml:"whitelist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeviceConfig struct {
|
||||||
|
Enable bool `yaml:"enable" default:"true"`
|
||||||
|
ShowAds bool `yaml:"show_ads"`
|
||||||
|
EnableSecurity bool `yaml:"enable_security"`
|
||||||
|
OnlyRealDevice bool `yaml:"only_real_device"`
|
||||||
|
SecuritySecret string `yaml:"security_secret"`
|
||||||
|
}
|
||||||
|
|
||||||
type SiteConfig struct {
|
type SiteConfig struct {
|
||||||
Host string `yaml:"Host" default:""`
|
Host string `yaml:"Host" default:""`
|
||||||
SiteName string `yaml:"SiteName" default:""`
|
SiteName string `yaml:"SiteName" default:""`
|
||||||
|
|||||||
@ -578,6 +578,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
authGroupRouter := router.Group("/v1/auth")
|
authGroupRouter := router.Group("/v1/auth")
|
||||||
|
authGroupRouter.Use(middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Check user is exist
|
// Check user is exist
|
||||||
@ -622,6 +623,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commonGroupRouter := router.Group("/v1/common")
|
commonGroupRouter := router.Group("/v1/common")
|
||||||
|
commonGroupRouter.Use(middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Get Ads
|
// Get Ads
|
||||||
@ -653,7 +655,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicAnnouncementGroupRouter := router.Group("/v1/public/announcement")
|
publicAnnouncementGroupRouter := router.Group("/v1/public/announcement")
|
||||||
publicAnnouncementGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicAnnouncementGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Query announcement
|
// Query announcement
|
||||||
@ -661,7 +663,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicDocumentGroupRouter := router.Group("/v1/public/document")
|
publicDocumentGroupRouter := router.Group("/v1/public/document")
|
||||||
publicDocumentGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicDocumentGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Get document detail
|
// Get document detail
|
||||||
@ -672,7 +674,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicOrderGroupRouter := router.Group("/v1/public/order")
|
publicOrderGroupRouter := router.Group("/v1/public/order")
|
||||||
publicOrderGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicOrderGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Close order
|
// Close order
|
||||||
@ -701,7 +703,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicPaymentGroupRouter := router.Group("/v1/public/payment")
|
publicPaymentGroupRouter := router.Group("/v1/public/payment")
|
||||||
publicPaymentGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicPaymentGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Get available payment methods
|
// Get available payment methods
|
||||||
@ -709,6 +711,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicPortalGroupRouter := router.Group("/v1/public/portal")
|
publicPortalGroupRouter := router.Group("/v1/public/portal")
|
||||||
|
publicPortalGroupRouter.Use(middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Purchase Checkout
|
// Purchase Checkout
|
||||||
@ -731,7 +734,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicSubscribeGroupRouter := router.Group("/v1/public/subscribe")
|
publicSubscribeGroupRouter := router.Group("/v1/public/subscribe")
|
||||||
publicSubscribeGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicSubscribeGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Get subscribe list
|
// Get subscribe list
|
||||||
@ -739,7 +742,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicTicketGroupRouter := router.Group("/v1/public/ticket")
|
publicTicketGroupRouter := router.Group("/v1/public/ticket")
|
||||||
publicTicketGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicTicketGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Update ticket status
|
// Update ticket status
|
||||||
@ -759,7 +762,7 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publicUserGroupRouter := router.Group("/v1/public/user")
|
publicUserGroupRouter := router.Group("/v1/public/user")
|
||||||
publicUserGroupRouter.Use(middleware.AuthMiddleware(serverCtx))
|
publicUserGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx))
|
||||||
|
|
||||||
{
|
{
|
||||||
// Query User Affiliate Count
|
// Query User Affiliate Count
|
||||||
|
|||||||
@ -92,6 +92,9 @@ func (l *UpdateAuthMethodConfigLogic) UpdateGlobal(method string) {
|
|||||||
if method == "mobile" {
|
if method == "mobile" {
|
||||||
initialize.Mobile(l.svcCtx)
|
initialize.Mobile(l.svcCtx)
|
||||||
}
|
}
|
||||||
|
if method == "device" {
|
||||||
|
initialize.Device(l.svcCtx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePlatformConfig(platform string, cfg map[string]interface{}) (interface{}, error) {
|
func validatePlatformConfig(platform string, cfg map[string]interface{}) (interface{}, error) {
|
||||||
|
|||||||
@ -107,6 +107,7 @@ func (l *DeviceLoginLogic) DeviceLogin(req *types.DeviceLoginRequest) (resp *typ
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", "device"),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Errorw("token generate error",
|
l.Errorw("token generate error",
|
||||||
|
|||||||
@ -107,6 +107,23 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res
|
|||||||
if err := l.svcCtx.UserModel.Update(l.ctx, userInfo); err != nil {
|
if err := l.svcCtx.UserModel.Update(l.ctx, userInfo); err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update user info failed: %v", err.Error())
|
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)
|
||||||
|
if err := bindLogic.BindDeviceToUser(req.Identifier, req.IP, req.UserAgent, userInfo.Id); err != nil {
|
||||||
|
l.Errorw("failed to bind device to user",
|
||||||
|
logger.Field("user_id", userInfo.Id),
|
||||||
|
logger.Field("identifier", req.Identifier),
|
||||||
|
logger.Field("error", err.Error()),
|
||||||
|
)
|
||||||
|
// Don't fail register if device binding fails, just log the error
|
||||||
|
}
|
||||||
|
loginType = "mobile"
|
||||||
|
}
|
||||||
|
|
||||||
// Generate session id
|
// Generate session id
|
||||||
sessionId := uuidx.NewUUID().String()
|
sessionId := uuidx.NewUUID().String()
|
||||||
// Generate token
|
// Generate token
|
||||||
@ -116,6 +133,7 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", loginType),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
||||||
|
|||||||
@ -124,6 +124,7 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r
|
|||||||
l.svcCtx.Redis.Del(l.ctx, cacheKey)
|
l.svcCtx.Redis.Del(l.ctx, cacheKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loginType := "pc"
|
||||||
// Bind device to user if identifier is provided
|
// Bind device to user if identifier is provided
|
||||||
if req.Identifier != "" {
|
if req.Identifier != "" {
|
||||||
bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx)
|
bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx)
|
||||||
@ -135,6 +136,7 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r
|
|||||||
)
|
)
|
||||||
// Don't fail login if device binding fails, just log the error
|
// Don't fail login if device binding fails, just log the error
|
||||||
}
|
}
|
||||||
|
loginType = "device"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate session id
|
// Generate session id
|
||||||
@ -146,6 +148,7 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", loginType),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
||||||
|
|||||||
@ -83,6 +83,22 @@ func (l *TelephoneResetPasswordLogic) TelephoneResetPassword(req *types.Telephon
|
|||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "update user password failed: %v", err.Error())
|
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)
|
||||||
|
if err := bindLogic.BindDeviceToUser(req.Identifier, req.IP, req.UserAgent, userInfo.Id); err != nil {
|
||||||
|
l.Errorw("failed to bind device to user",
|
||||||
|
logger.Field("user_id", userInfo.Id),
|
||||||
|
logger.Field("identifier", req.Identifier),
|
||||||
|
logger.Field("error", err.Error()),
|
||||||
|
)
|
||||||
|
// Don't fail register if device binding fails, just log the error
|
||||||
|
}
|
||||||
|
loginType = "mobile"
|
||||||
|
}
|
||||||
|
|
||||||
// Generate session id
|
// Generate session id
|
||||||
sessionId := uuidx.NewUUID().String()
|
sessionId := uuidx.NewUUID().String()
|
||||||
// Generate token
|
// Generate token
|
||||||
@ -92,6 +108,7 @@ func (l *TelephoneResetPasswordLogic) TelephoneResetPassword(req *types.Telephon
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", loginType),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Errorw("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
l.Errorw("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
||||||
|
|||||||
@ -139,6 +139,8 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
loginType := "pc"
|
||||||
|
|
||||||
// Bind device to user if identifier is provided
|
// Bind device to user if identifier is provided
|
||||||
if req.Identifier != "" {
|
if req.Identifier != "" {
|
||||||
bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx)
|
bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx)
|
||||||
@ -150,6 +152,7 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR
|
|||||||
)
|
)
|
||||||
// Don't fail register if device binding fails, just log the error
|
// Don't fail register if device binding fails, just log the error
|
||||||
}
|
}
|
||||||
|
loginType = "mobile"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate session id
|
// Generate session id
|
||||||
@ -161,6 +164,7 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", loginType),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
||||||
|
|||||||
@ -79,6 +79,7 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log
|
|||||||
if !tool.VerifyPassWord(req.Password, userInfo.Password) {
|
if !tool.VerifyPassWord(req.Password, userInfo.Password) {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password")
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password")
|
||||||
}
|
}
|
||||||
|
loginType := "pc"
|
||||||
|
|
||||||
// Bind device to user if identifier is provided
|
// Bind device to user if identifier is provided
|
||||||
if req.Identifier != "" {
|
if req.Identifier != "" {
|
||||||
@ -91,6 +92,7 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log
|
|||||||
)
|
)
|
||||||
// Don't fail login if device binding fails, just log the error
|
// Don't fail login if device binding fails, just log the error
|
||||||
}
|
}
|
||||||
|
loginType = "device"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate session id
|
// Generate session id
|
||||||
@ -102,6 +104,7 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", loginType),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
||||||
|
|||||||
@ -125,7 +125,7 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp *
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
loginType := "pc"
|
||||||
// Bind device to user if identifier is provided
|
// Bind device to user if identifier is provided
|
||||||
if req.Identifier != "" {
|
if req.Identifier != "" {
|
||||||
bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx)
|
bindLogic := NewBindDeviceLogic(l.ctx, l.svcCtx)
|
||||||
@ -137,6 +137,7 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp *
|
|||||||
)
|
)
|
||||||
// Don't fail register if device binding fails, just log the error
|
// Don't fail register if device binding fails, just log the error
|
||||||
}
|
}
|
||||||
|
loginType = "device"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate session id
|
// Generate session id
|
||||||
@ -148,6 +149,7 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp *
|
|||||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
jwt.WithOption("UserId", userInfo.Id),
|
jwt.WithOption("UserId", userInfo.Id),
|
||||||
jwt.WithOption("SessionId", sessionId),
|
jwt.WithOption("SessionId", sessionId),
|
||||||
|
jwt.WithOption("LoginType", loginType),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error()))
|
||||||
|
|||||||
@ -40,6 +40,8 @@ func AuthMiddleware(svc *svc.ServiceContext) func(c *gin.Context) {
|
|||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loginType := claims["LoginType"].(string)
|
||||||
// get user id from token
|
// get user id from token
|
||||||
userId := int64(claims["UserId"].(float64))
|
userId := int64(claims["UserId"].(float64))
|
||||||
// get session id from token
|
// get session id from token
|
||||||
@ -77,6 +79,7 @@ func AuthMiddleware(svc *svc.ServiceContext) func(c *gin.Context) {
|
|||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ctx = context.WithValue(ctx, constant.LoginType, loginType)
|
||||||
ctx = context.WithValue(ctx, constant.CtxKeyUser, userInfo)
|
ctx = context.WithValue(ctx, constant.CtxKeyUser, userInfo)
|
||||||
ctx = context.WithValue(ctx, constant.CtxKeySessionID, sessionId)
|
ctx = context.WithValue(ctx, constant.CtxKeySessionID, sessionId)
|
||||||
c.Request = c.Request.WithContext(ctx)
|
c.Request = c.Request.WithContext(ctx)
|
||||||
|
|||||||
286
internal/middleware/deviceMiddleware.go
Normal file
286
internal/middleware/deviceMiddleware.go
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
|
pkgaes "github.com/perfect-panel/server/pkg/aes"
|
||||||
|
"github.com/perfect-panel/server/pkg/constant"
|
||||||
|
"github.com/perfect-panel/server/pkg/result"
|
||||||
|
"github.com/perfect-panel/server/pkg/xerr"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
noWritten = -1
|
||||||
|
defaultStatus = http.StatusOK
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeviceMiddleware(srvCtx *svc.ServiceContext) func(c *gin.Context) {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
loginType := c.GetString(string(constant.LoginType))
|
||||||
|
if loginType == "" {
|
||||||
|
loginType = c.GetHeader("Login-Type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if loginType != "device" {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !srvCtx.Config.Device.Enable || srvCtx.Config.Device.SecuritySecret == "" {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rw := NewResponseWriter(c, srvCtx)
|
||||||
|
if !rw.Decrypt() {
|
||||||
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidCiphertext), "Invalid ciphertext"))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Writer = rw
|
||||||
|
c.Next()
|
||||||
|
rw.FlushAbort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResponseWriter(c *gin.Context, srvCtx *svc.ServiceContext) (rw *ResponseWriter) {
|
||||||
|
rw = &ResponseWriter{
|
||||||
|
c: c,
|
||||||
|
body: new(bytes.Buffer),
|
||||||
|
ResponseWriter: c.Writer,
|
||||||
|
}
|
||||||
|
rw.encryptionKey = srvCtx.Config.Device.SecuritySecret
|
||||||
|
rw.encryptionMethod = "AES"
|
||||||
|
rw.encryption = true
|
||||||
|
return rw
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Encrypt() {
|
||||||
|
if !rw.encryption {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf := rw.body.Bytes()
|
||||||
|
params := map[string]interface{}{}
|
||||||
|
err := json.Unmarshal(buf, ¶ms)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := params["data"]
|
||||||
|
if data != nil {
|
||||||
|
var jsonData []byte
|
||||||
|
str, ok := data.(string)
|
||||||
|
if ok {
|
||||||
|
jsonData = []byte(str)
|
||||||
|
} else {
|
||||||
|
jsonData, _ = json.Marshal(data)
|
||||||
|
}
|
||||||
|
encrypt, iv, err := pkgaes.Encrypt(jsonData, rw.encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params["data"] = map[string]interface{}{
|
||||||
|
"data": encrypt,
|
||||||
|
"time": iv,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
marshal, _ := json.Marshal(params)
|
||||||
|
rw.body.Reset()
|
||||||
|
rw.body.Write(marshal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Decrypt() bool {
|
||||||
|
if !rw.encryption {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断url链接中是否存在data和iv数据,存在就进行解密并设置回去
|
||||||
|
query := rw.c.Request.URL.Query()
|
||||||
|
dataStr := query.Get("data")
|
||||||
|
timeStr := query.Get("time")
|
||||||
|
if dataStr != "" && timeStr != "" {
|
||||||
|
decrypt, err := pkgaes.Decrypt(dataStr, rw.encryptionKey, timeStr)
|
||||||
|
if err == nil {
|
||||||
|
params := map[string]interface{}{}
|
||||||
|
err = json.Unmarshal([]byte(decrypt), ¶ms)
|
||||||
|
if err == nil {
|
||||||
|
for k, v := range params {
|
||||||
|
query.Set(k, fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
query.Del("data")
|
||||||
|
query.Del("time")
|
||||||
|
rw.c.Request.RequestURI = fmt.Sprintf("%s?%s", rw.c.Request.RequestURI[:strings.Index(rw.c.Request.RequestURI, "?")], query.Encode())
|
||||||
|
rw.c.Request.URL.RawQuery = query.Encode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断body是否存在数据,存在就尝试解密,并设置回去
|
||||||
|
body, err := io.ReadAll(rw.c.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(body) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
params := map[string]interface{}{}
|
||||||
|
err = json.Unmarshal(body, ¶ms)
|
||||||
|
data := params["data"]
|
||||||
|
nonce := params["time"]
|
||||||
|
if err != nil || data == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
str, ok := data.(string)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
iv, ok := nonce.(string)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt, err := pkgaes.Decrypt(str, rw.encryptionKey, iv)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
rw.c.Request.Body = io.NopCloser(bytes.NewBuffer([]byte(decrypt)))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) FlushAbort() {
|
||||||
|
defer rw.c.Abort()
|
||||||
|
responseBody := rw.body.String()
|
||||||
|
fmt.Println("Original Response Body:", responseBody)
|
||||||
|
rw.flush = true
|
||||||
|
if rw.encryption {
|
||||||
|
rw.Encrypt()
|
||||||
|
}
|
||||||
|
_, err := rw.Write(rw.body.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
size int
|
||||||
|
status int
|
||||||
|
flush bool
|
||||||
|
body *bytes.Buffer
|
||||||
|
c *gin.Context
|
||||||
|
encryption bool
|
||||||
|
encryptionKey string
|
||||||
|
encryptionMethod string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Unwrap() http.ResponseWriter {
|
||||||
|
return rw.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
|
func (rw *ResponseWriter) reset(writer http.ResponseWriter) {
|
||||||
|
rw.ResponseWriter = writer
|
||||||
|
rw.size = noWritten
|
||||||
|
rw.status = defaultStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) WriteHeader(code int) {
|
||||||
|
if code > 0 && rw.status != code {
|
||||||
|
if rw.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rw.status = code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) WriteHeaderNow() {
|
||||||
|
if !rw.Written() {
|
||||||
|
rw.size = 0
|
||||||
|
rw.ResponseWriter.WriteHeader(rw.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Write(data []byte) (n int, err error) {
|
||||||
|
if rw.flush {
|
||||||
|
rw.WriteHeaderNow()
|
||||||
|
n, err = rw.ResponseWriter.Write(data)
|
||||||
|
rw.size += n
|
||||||
|
} else {
|
||||||
|
rw.body.Write(data)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) WriteString(s string) (n int, err error) {
|
||||||
|
if rw.flush {
|
||||||
|
rw.WriteHeaderNow()
|
||||||
|
n, err = rw.ResponseWriter.Write([]byte(s))
|
||||||
|
rw.size += n
|
||||||
|
} else {
|
||||||
|
rw.body.Write([]byte(s))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Status() int {
|
||||||
|
return rw.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Size() int {
|
||||||
|
return rw.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Written() bool {
|
||||||
|
return rw.size != noWritten
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hijack implements the http.Hijacker interface.
|
||||||
|
func (rw *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
if rw.size < 0 {
|
||||||
|
rw.size = 0
|
||||||
|
}
|
||||||
|
return rw.ResponseWriter.(http.Hijacker).Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseNotify implements the http.CloseNotifier interface.
|
||||||
|
func (rw *ResponseWriter) CloseNotify() <-chan bool {
|
||||||
|
// 通过 r.Context().Done() 来监听请求的取消
|
||||||
|
done := rw.c.Request.Context().Done()
|
||||||
|
closed := make(chan bool)
|
||||||
|
|
||||||
|
// 当上下文被取消时,通过 closed channel 发送通知
|
||||||
|
go func() {
|
||||||
|
<-done
|
||||||
|
closed <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
return closed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush implements the http.Flusher interface.
|
||||||
|
func (rw *ResponseWriter) Flush() {
|
||||||
|
rw.WriteHeaderNow()
|
||||||
|
rw.ResponseWriter.(http.Flusher).Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *ResponseWriter) Pusher() (pusher http.Pusher) {
|
||||||
|
if pusher, ok := rw.ResponseWriter.(http.Pusher); ok {
|
||||||
|
return pusher
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -1752,12 +1752,13 @@ type RenewalOrderResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResetPasswordRequest struct {
|
type ResetPasswordRequest struct {
|
||||||
Email string `json:"email" validate:"required"`
|
Identifier string `json:"identifier"`
|
||||||
Password string `json:"password" validate:"required"`
|
Email string `json:"email" validate:"required"`
|
||||||
Code string `json:"code,optional"`
|
Password string `json:"password" validate:"required"`
|
||||||
IP string `header:"X-Original-Forwarded-For"`
|
Code string `json:"code,optional"`
|
||||||
UserAgent string `header:"User-Agent"`
|
IP string `header:"X-Original-Forwarded-For"`
|
||||||
CfToken string `json:"cf_token,optional"`
|
UserAgent string `header:"User-Agent"`
|
||||||
|
CfToken string `json:"cf_token,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResetSortRequest struct {
|
type ResetSortRequest struct {
|
||||||
@ -2128,6 +2129,7 @@ type TelephoneRegisterRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TelephoneResetPasswordRequest struct {
|
type TelephoneResetPasswordRequest struct {
|
||||||
|
Identifier string `json:"identifier"`
|
||||||
Telephone string `json:"telephone" validate:"required"`
|
Telephone string `json:"telephone" validate:"required"`
|
||||||
TelephoneAreaCode string `json:"telephone_area_code" validate:"required"`
|
TelephoneAreaCode string `json:"telephone_area_code" validate:"required"`
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
|
|||||||
@ -8,4 +8,5 @@ const (
|
|||||||
CtxKeyRequestHost CtxKey = "requestHost"
|
CtxKeyRequestHost CtxKey = "requestHost"
|
||||||
CtxKeyPlatform CtxKey = "platform"
|
CtxKeyPlatform CtxKey = "platform"
|
||||||
CtxKeyPayment CtxKey = "payment"
|
CtxKeyPayment CtxKey = "payment"
|
||||||
|
LoginType CtxKey = "loginType"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3,5 +3,5 @@ package tool
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestEncodePassWord(t *testing.T) {
|
func TestEncodePassWord(t *testing.T) {
|
||||||
t.Logf("EncodePassWord: %v", EncodePassWord(""))
|
t.Logf("EncodePassWord: %v", EncodePassWord("password"))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user