diff --git a/app/main/api/desc/front/agent.api b/app/main/api/desc/front/agent.api index 3ec20f9..4ee0e88 100644 --- a/app/main/api/desc/front/agent.api +++ b/app/main/api/desc/front/agent.api @@ -35,7 +35,6 @@ type ProductConfig { PriceRangeMin float64 `json:"price_range_min"` PriceRangeMax float64 `json:"price_range_max"` } - @server ( prefix: api/v1/agent group: agent @@ -46,6 +45,16 @@ service main { @handler GetAgentInfo get /info returns (AgentInfoResp) + @handler GetAgentRevenueInfo + get /revenue (GetAgentRevenueInfoReq) returns (GetAgentRevenueInfoResp) +} +@server ( + prefix: api/v1/agent + group: agent + jwt: JwtAuth + middleware: UserAuthInterceptor +) +service main { // 查询代理申请状态 @handler GetAgentAuditStatus get /audit/status returns (AgentAuditStatusResp) @@ -169,6 +178,8 @@ type ( prefix: api/v1/agent group: agent jwt: JwtAuth + middleware: UserAuthInterceptor + ) service main { @handler GetAgentMembershipProductConfig @@ -204,11 +215,10 @@ type ( prefix: api/v1/agent group: agent jwt: JwtAuth + middleware: UserAuthInterceptor + ) service main { - @handler GetAgentRevenueInfo - get /revenue (GetAgentRevenueInfoReq) returns (GetAgentRevenueInfoResp) - @handler GetAgentCommission get /commission (GetCommissionReq) returns (GetCommissionResp) @@ -327,6 +337,8 @@ type ( @server ( prefix: api/v1/agent group: agent + middleware: AuthInterceptor + ) service main { // 提交代理申请 diff --git a/app/main/api/desc/front/pay.api b/app/main/api/desc/front/pay.api index 5f363ab..dc4b246 100644 --- a/app/main/api/desc/front/pay.api +++ b/app/main/api/desc/front/pay.api @@ -30,7 +30,8 @@ service main { prefix: api/v1 group: pay jwt: JwtAuth - middleware: SourceInterceptor + middleware: UserAuthInterceptor + ) service main { // 支付 diff --git a/app/main/api/desc/front/product.api b/app/main/api/desc/front/product.api index 9fb20f3..e006b07 100644 --- a/app/main/api/desc/front/product.api +++ b/app/main/api/desc/front/product.api @@ -26,6 +26,8 @@ type Product { prefix: api/v1/product group: product jwt: JwtAuth + middleware: UserAuthInterceptor + ) service main { @handler GetProductByID diff --git a/app/main/api/desc/front/query.api b/app/main/api/desc/front/query.api index 35a36d4..353b681 100644 --- a/app/main/api/desc/front/query.api +++ b/app/main/api/desc/front/query.api @@ -70,6 +70,8 @@ type ( prefix: api/v1 group: query jwt: JwtAuth + middleware: UserAuthInterceptor + ) service main { @doc "query service" @@ -81,6 +83,8 @@ service main { prefix: api/v1 group: query jwt: JwtAuth + middleware: UserAuthInterceptor + ) service main { @doc "获取查询临时订单" diff --git a/app/main/api/desc/front/user.api b/app/main/api/desc/front/user.api index ec267fc..bed01c5 100644 --- a/app/main/api/desc/front/user.api +++ b/app/main/api/desc/front/user.api @@ -14,6 +14,7 @@ type User { Id int64 `json:"id"` Mobile string `json:"mobile"` NickName string `json:"nickName"` + UserType int64 `json:"userType"` } //no need login @@ -22,22 +23,10 @@ type User { group: user ) service main { - @doc "register" - @handler register - post /user/register (RegisterReq) returns (RegisterResp) - - @doc "mobile login" - @handler mobileLogin - post /user/mobileLogin (MobileLoginReq) returns (MobileLoginResp) - @doc "mobile code login" @handler mobileCodeLogin post /user/mobileCodeLogin (MobileCodeLoginReq) returns (MobileCodeLoginResp) - @doc "agent mobile code login" - @handler agentMobileCodeLogin - post /user/agent_mobile_code_login (MobileCodeLoginReq) returns (MobileCodeLoginResp) - @doc "wechat mini auth" @handler wxMiniAuth post /user/wxMiniAuth (WXMiniAuthReq) returns (WXMiniAuthResp) @@ -47,31 +36,6 @@ service main { post /user/wxh5Auth (WXH5AuthReq) returns (WXH5AuthResp) } -type ( - RegisterReq { - Mobile string `json:"mobile" validate:"required,mobile"` - Password string `json:"password" validate:"required,min=11,max=11,password"` - Code string `json:"code" validate:"required"` - } - RegisterResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - -type ( - MobileLoginReq { - Mobile string `json:"mobile" validate:"required,mobile"` - Password string `json:"password" validate:"required"` - } - MobileLoginResp { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` - } -) - type ( MobileCodeLoginReq { Mobile string `json:"mobile"` @@ -107,6 +71,16 @@ type ( RefreshAfter int64 `json:"refreshAfter"` } ) +@server ( + prefix: api/v1 + group: user + middleware: AuthInterceptor +) +service main { + @doc "绑定手机号" + @handler bindMobile + post /user/bindMobile (BindMobileReq) returns (BindMobileResp) +} //need login @server ( @@ -125,10 +99,6 @@ service main { @handler cancelOut post /user/cancelOut - - @doc "绑定手机号" - @handler bindMobile - post /user/bindMobile (BindMobileReq) returns (BindMobileResp) } type ( @@ -141,6 +111,9 @@ type ( Code string `json:"code" validate:"required"` } BindMobileResp { + AccessToken string `json:"accessToken"` + AccessExpire int64 `json:"accessExpire"` + RefreshAfter int64 `json:"refreshAfter"` } ) diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index 8c589e5..1ac26d0 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -516,113 +516,132 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( []rest.Route{ - { - Method: http.MethodGet, - Path: "/audit/status", - Handler: agent.GetAgentAuditStatusHandler(serverCtx), - }, - { - Method: http.MethodPost, - Path: "/generating_link", - Handler: agent.GeneratingLinkHandler(serverCtx), - }, { Method: http.MethodGet, Path: "/info", Handler: agent.GetAgentInfoHandler(serverCtx), }, - { - Method: http.MethodGet, - Path: "/product_config", - Handler: agent.GetAgentProductConfigHandler(serverCtx), - }, - { - Method: http.MethodPost, - Path: "/real_name", - Handler: agent.AgentRealNameHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/subordinate/contribution/detail", - Handler: agent.GetAgentSubordinateContributionDetailHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/subordinate/list", - Handler: agent.GetAgentSubordinateListHandler(serverCtx), - }, - }, - rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), - rest.WithPrefix("/api/v1/agent"), - ) - - server.AddRoutes( - []rest.Route{ - { - Method: http.MethodPost, - Path: "/membership/save_user_config", - Handler: agent.SaveAgentMembershipUserConfigHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/membership/user_config", - Handler: agent.GetAgentMembershipProductConfigHandler(serverCtx), - }, - }, - rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), - rest.WithPrefix("/api/v1/agent"), - ) - - server.AddRoutes( - []rest.Route{ - { - Method: http.MethodGet, - Path: "/commission", - Handler: agent.GetAgentCommissionHandler(serverCtx), - }, - { - Method: http.MethodPost, - Path: "/membership/activate", - Handler: agent.ActivateAgentMembershipHandler(serverCtx), - }, { Method: http.MethodGet, Path: "/revenue", Handler: agent.GetAgentRevenueInfoHandler(serverCtx), }, - { - Method: http.MethodGet, - Path: "/rewards", - Handler: agent.GetAgentRewardsHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/withdrawal", - Handler: agent.GetAgentWithdrawalHandler(serverCtx), - }, - { - Method: http.MethodPost, - Path: "/withdrawal", - Handler: agent.AgentWithdrawalHandler(serverCtx), - }, }, rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), rest.WithPrefix("/api/v1/agent"), ) server.AddRoutes( - []rest.Route{ - { - Method: http.MethodPost, - Path: "/apply", - Handler: agent.ApplyForAgentHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/link", - Handler: agent.GetLinkDataHandler(serverCtx), - }, - }, + rest.WithMiddlewares( + []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Route{ + { + Method: http.MethodGet, + Path: "/audit/status", + Handler: agent.GetAgentAuditStatusHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/generating_link", + Handler: agent.GeneratingLinkHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/product_config", + Handler: agent.GetAgentProductConfigHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/real_name", + Handler: agent.AgentRealNameHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/subordinate/contribution/detail", + Handler: agent.GetAgentSubordinateContributionDetailHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/subordinate/list", + Handler: agent.GetAgentSubordinateListHandler(serverCtx), + }, + }..., + ), + rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), + rest.WithPrefix("/api/v1/agent"), + ) + + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Route{ + { + Method: http.MethodPost, + Path: "/membership/save_user_config", + Handler: agent.SaveAgentMembershipUserConfigHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/membership/user_config", + Handler: agent.GetAgentMembershipProductConfigHandler(serverCtx), + }, + }..., + ), + rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), + rest.WithPrefix("/api/v1/agent"), + ) + + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Route{ + { + Method: http.MethodGet, + Path: "/commission", + Handler: agent.GetAgentCommissionHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/membership/activate", + Handler: agent.ActivateAgentMembershipHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/rewards", + Handler: agent.GetAgentRewardsHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/withdrawal", + Handler: agent.GetAgentWithdrawalHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/withdrawal", + Handler: agent.AgentWithdrawalHandler(serverCtx), + }, + }..., + ), + rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), + rest.WithPrefix("/api/v1/agent"), + ) + + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.AuthInterceptor}, + []rest.Route{ + { + Method: http.MethodPost, + Path: "/apply", + Handler: agent.ApplyForAgentHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/link", + Handler: agent.GetLinkDataHandler(serverCtx), + }, + }..., + ), rest.WithPrefix("/api/v1/agent"), ) @@ -690,7 +709,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.SourceInterceptor}, + []rest.Middleware{serverCtx.UserAuthInterceptor}, []rest.Route{ { Method: http.MethodPost, @@ -714,18 +733,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { ) server.AddRoutes( - []rest.Route{ - { - Method: http.MethodGet, - Path: "/:id", - Handler: product.GetProductByIDHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/en/:product_en", - Handler: product.GetProductByEnHandler(serverCtx), - }, - }, + rest.WithMiddlewares( + []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Route{ + { + Method: http.MethodGet, + Path: "/:id", + Handler: product.GetProductByIDHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/en/:product_en", + Handler: product.GetProductByEnHandler(serverCtx), + }, + }..., + ), rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), rest.WithPrefix("/api/v1/product"), ) @@ -762,63 +784,69 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { ) server.AddRoutes( - []rest.Route{ - { - // query service - Method: http.MethodPost, - Path: "/query/service/:product", - Handler: query.QueryServiceHandler(serverCtx), - }, - }, + rest.WithMiddlewares( + []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Route{ + { + // query service + Method: http.MethodPost, + Path: "/query/service/:product", + Handler: query.QueryServiceHandler(serverCtx), + }, + }..., + ), rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), rest.WithPrefix("/api/v1"), ) server.AddRoutes( - []rest.Route{ - { - // 生成分享链接 - Method: http.MethodPost, - Path: "/query/generate_share_link", - Handler: query.QueryGenerateShareLinkHandler(serverCtx), - }, - { - // 查询列表 - Method: http.MethodGet, - Path: "/query/list", - Handler: query.QueryListHandler(serverCtx), - }, - { - // 查询详情 按订单号 付款查询时 - Method: http.MethodGet, - Path: "/query/orderId/:order_id", - Handler: query.QueryDetailByOrderIdHandler(serverCtx), - }, - { - // 查询详情 按订单号 - Method: http.MethodGet, - Path: "/query/orderNo/:order_no", - Handler: query.QueryDetailByOrderNoHandler(serverCtx), - }, - { - // 获取查询临时订单 - Method: http.MethodGet, - Path: "/query/provisional_order/:id", - Handler: query.QueryProvisionalOrderHandler(serverCtx), - }, - { - // 重试查询 - Method: http.MethodPost, - Path: "/query/retry/:id", - Handler: query.QueryRetryHandler(serverCtx), - }, - { - // 更新查询数据 - Method: http.MethodPost, - Path: "/query/update_data", - Handler: query.UpdateQueryDataHandler(serverCtx), - }, - }, + rest.WithMiddlewares( + []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Route{ + { + // 生成分享链接 + Method: http.MethodPost, + Path: "/query/generate_share_link", + Handler: query.QueryGenerateShareLinkHandler(serverCtx), + }, + { + // 查询列表 + Method: http.MethodGet, + Path: "/query/list", + Handler: query.QueryListHandler(serverCtx), + }, + { + // 查询详情 按订单号 付款查询时 + Method: http.MethodGet, + Path: "/query/orderId/:order_id", + Handler: query.QueryDetailByOrderIdHandler(serverCtx), + }, + { + // 查询详情 按订单号 + Method: http.MethodGet, + Path: "/query/orderNo/:order_no", + Handler: query.QueryDetailByOrderNoHandler(serverCtx), + }, + { + // 获取查询临时订单 + Method: http.MethodGet, + Path: "/query/provisional_order/:id", + Handler: query.QueryProvisionalOrderHandler(serverCtx), + }, + { + // 重试查询 + Method: http.MethodPost, + Path: "/query/retry/:id", + Handler: query.QueryRetryHandler(serverCtx), + }, + { + // 更新查询数据 + Method: http.MethodPost, + Path: "/query/update_data", + Handler: query.UpdateQueryDataHandler(serverCtx), + }, + }..., + ), rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), rest.WithPrefix("/api/v1"), ) @@ -848,30 +876,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( []rest.Route{ - { - // agent mobile code login - Method: http.MethodPost, - Path: "/user/agent_mobile_code_login", - Handler: user.AgentMobileCodeLoginHandler(serverCtx), - }, { // mobile code login Method: http.MethodPost, Path: "/user/mobileCodeLogin", Handler: user.MobileCodeLoginHandler(serverCtx), }, - { - // mobile login - Method: http.MethodPost, - Path: "/user/mobileLogin", - Handler: user.MobileLoginHandler(serverCtx), - }, - { - // register - Method: http.MethodPost, - Path: "/user/register", - Handler: user.RegisterHandler(serverCtx), - }, { // wechat mini auth Method: http.MethodPost, @@ -888,14 +898,23 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { rest.WithPrefix("/api/v1"), ) + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.AuthInterceptor}, + []rest.Route{ + { + // 绑定手机号 + Method: http.MethodPost, + Path: "/user/bindMobile", + Handler: user.BindMobileHandler(serverCtx), + }, + }..., + ), + rest.WithPrefix("/api/v1"), + ) + server.AddRoutes( []rest.Route{ - { - // 绑定手机号 - Method: http.MethodPost, - Path: "/user/bindMobile", - Handler: user.BindMobileHandler(serverCtx), - }, { Method: http.MethodPost, Path: "/user/cancelOut", diff --git a/app/main/api/internal/handler/user/agentmobilecodeloginhandler.go b/app/main/api/internal/handler/user/agentmobilecodeloginhandler.go deleted file mode 100644 index e85ff33..0000000 --- a/app/main/api/internal/handler/user/agentmobilecodeloginhandler.go +++ /dev/null @@ -1,30 +0,0 @@ -package user - -import ( - "net/http" - - "tydata-server/app/main/api/internal/logic/user" - "tydata-server/app/main/api/internal/svc" - "tydata-server/app/main/api/internal/types" - "tydata-server/common/result" - "tydata-server/pkg/lzkit/validator" - - "github.com/zeromicro/go-zero/rest/httpx" -) - -func AgentMobileCodeLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req types.MobileCodeLoginReq - if err := httpx.Parse(r, &req); err != nil { - result.ParamErrorResult(r, w, err) - return - } - if err := validator.Validate(req); err != nil { - result.ParamValidateErrorResult(r, w, err) - return - } - l := user.NewAgentMobileCodeLoginLogic(r.Context(), svcCtx) - resp, err := l.AgentMobileCodeLogin(&req) - result.HttpResult(r, w, resp, err) - } -} diff --git a/app/main/api/internal/handler/user/mobileloginhandler.go b/app/main/api/internal/handler/user/mobileloginhandler.go deleted file mode 100644 index acba9c2..0000000 --- a/app/main/api/internal/handler/user/mobileloginhandler.go +++ /dev/null @@ -1,30 +0,0 @@ -package user - -import ( - "net/http" - - "tydata-server/app/main/api/internal/logic/user" - "tydata-server/app/main/api/internal/svc" - "tydata-server/app/main/api/internal/types" - "tydata-server/common/result" - "tydata-server/pkg/lzkit/validator" - - "github.com/zeromicro/go-zero/rest/httpx" -) - -func MobileLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req types.MobileLoginReq - if err := httpx.Parse(r, &req); err != nil { - result.ParamErrorResult(r, w, err) - return - } - if err := validator.Validate(req); err != nil { - result.ParamValidateErrorResult(r, w, err) - return - } - l := user.NewMobileLoginLogic(r.Context(), svcCtx) - resp, err := l.MobileLogin(&req) - result.HttpResult(r, w, resp, err) - } -} diff --git a/app/main/api/internal/handler/user/registerhandler.go b/app/main/api/internal/handler/user/registerhandler.go deleted file mode 100644 index 2cabf91..0000000 --- a/app/main/api/internal/handler/user/registerhandler.go +++ /dev/null @@ -1,30 +0,0 @@ -package user - -import ( - "net/http" - - "tydata-server/app/main/api/internal/logic/user" - "tydata-server/app/main/api/internal/svc" - "tydata-server/app/main/api/internal/types" - "tydata-server/common/result" - "tydata-server/pkg/lzkit/validator" - - "github.com/zeromicro/go-zero/rest/httpx" -) - -func RegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req types.RegisterReq - if err := httpx.Parse(r, &req); err != nil { - result.ParamErrorResult(r, w, err) - return - } - if err := validator.Validate(req); err != nil { - result.ParamValidateErrorResult(r, w, err) - return - } - l := user.NewRegisterLogic(r.Context(), svcCtx) - resp, err := l.Register(&req) - result.HttpResult(r, w, resp, err) - } -} diff --git a/app/main/api/internal/logic/admin_auth/adminloginlogic.go b/app/main/api/internal/logic/admin_auth/adminloginlogic.go index caaeb3b..4ed62e5 100644 --- a/app/main/api/internal/logic/admin_auth/adminloginlogic.go +++ b/app/main/api/internal/logic/admin_auth/adminloginlogic.go @@ -5,6 +5,7 @@ import ( "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" + "tydata-server/app/main/model" jwtx "tydata-server/common/jwt" "tydata-server/common/xerr" "tydata-server/pkg/lzkit/crypto" @@ -71,7 +72,14 @@ func (l *AdminLoginLogic) AdminLogin(req *types.AdminLoginReq) (resp *types.Admi // 5. 生成token refreshToken := l.svcCtx.Config.JwtAuth.RefreshAfter expiresAt := l.svcCtx.Config.JwtAuth.AccessExpire - token, err := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, expiresAt) + claims := jwtx.JwtClaims{ + UserId: user.Id, + AgentId: 0, + Platform: model.PlatformAdmin, + UserType: model.UserTypeAdmin, + IsAgent: model.AgentStatusNo, + } + token, err := jwtx.GenerateJwtToken(claims, l.svcCtx.Config.JwtAuth.AccessSecret, expiresAt) if err != nil { return nil, errors.Wrapf(xerr.NewErrMsg("生成token失败"), "用户登录, 生成token失败, 用户名: %s", req.Username) } diff --git a/app/main/api/internal/logic/agent/applyforagentlogic.go b/app/main/api/internal/logic/agent/applyforagentlogic.go index 9b60316..16a2ee4 100644 --- a/app/main/api/internal/logic/agent/applyforagentlogic.go +++ b/app/main/api/internal/logic/agent/applyforagentlogic.go @@ -6,7 +6,7 @@ import ( "fmt" "time" "tydata-server/app/main/model" - jwtx "tydata-server/common/jwt" + "tydata-server/common/ctxdata" "tydata-server/common/xerr" "tydata-server/pkg/lzkit/crypto" @@ -35,6 +35,10 @@ func NewApplyForAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *App } func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *types.AgentApplyResp, err error) { + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) + if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, %v", err) + } secretKey := l.svcCtx.Config.Encrypt.SecretKey encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) if err != nil { @@ -63,29 +67,20 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 读取数据库获取用户失败, mobile: %s, err: %+v", encryptedMobile, err) } if user == nil { - user = &model.User{Mobile: sql.NullString{String: encryptedMobile, Valid: true}} - // if len(main.Nickname) == 0 { - // main.Nickname = encryptedMobile - // } - insertResult, userInsertErr := l.svcCtx.UserModel.Insert(transCtx, session, user) - if userInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, userInsertErr) + userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 注册用户失败: %+v", err) } - lastId, lastInsertIdErr := insertResult.LastInsertId() - if lastInsertIdErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user) - } - user.Id = lastId - userID = lastId - userAuth := new(model.UserAuth) - userAuth.UserId = lastId - userAuth.AuthKey = encryptedMobile - userAuth.AuthType = model.UserAuthTypeAgentDirect - if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(transCtx, session, userAuth); userAuthInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 数据库插入用户认证失败, err:%+v", userAuthInsertErr) + } else { + if claims != nil && claims.UserType == model.UserTypeTemp { + // 临时用户,转为正式用户 + err = l.svcCtx.UserService.TempUserBindUser(l.ctx, session, user.Id) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 注册用户失败: %+v", err) + } } + userID = user.Id } - userID = user.Id // 使用SelectBuilder构建查询,查找符合user_id的记录并按创建时间降序排序获取最新一条 builder := l.svcCtx.AgentAuditModel.SelectBuilder().Where("user_id = ?", user.Id).OrderBy("create_time DESC").Limit(1) @@ -113,23 +108,12 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 保存代理审核信息失败: %v", insetAgentAuditErr) } - //agentAuditID, _ := agentAuditInsert.LastInsertId() - //agentAuditRow, findAgentAuditModelErr := l.svcCtx.AgentAuditModel.FindOne(l.ctx, agentAuditID) - //if findAgentAuditModelErr != nil { - // return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 查找代理审核信息失败: %v", insetAgentAuditErr) - //} - //agentAuditRow.Status = 1 - //updateAgentAuditErr := l.svcCtx.AgentAuditModel.UpdateWithVersion(transCtx, session, agentAuditRow) - //if updateAgentAuditErr != nil { - // return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 通过代理审核失败: %+v", updateAgentAuditErr) - //} - // 新增代理 var agentModel model.Agent agentModel.Mobile = agentAudit.Mobile agentModel.Region = agentAudit.Region - agentModel.LevelName = model.AgentLeveNameNormal agentModel.UserId = agentAudit.UserId + agentModel.LevelName = model.AgentLeveNameNormal agentModelInsert, insertAgentModelErr := l.svcCtx.AgentModel.Insert(transCtx, session, &agentModel) if insertAgentModelErr != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 新增代理失败: %+v", insertAgentModelErr) @@ -169,9 +153,9 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type if transErr != nil { return nil, transErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 生成token失败 : %d", userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID) } // 获取当前时间戳 diff --git a/app/main/api/internal/logic/agent/getagentrevenueinfologic.go b/app/main/api/internal/logic/agent/getagentrevenueinfologic.go index 570e95c..99fdef0 100644 --- a/app/main/api/internal/logic/agent/getagentrevenueinfologic.go +++ b/app/main/api/internal/logic/agent/getagentrevenueinfologic.go @@ -31,9 +31,31 @@ func NewGetAgentRevenueInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext } func (l *GetAgentRevenueInfoLogic) GetAgentRevenueInfo(req *types.GetAgentRevenueInfoReq) (resp *types.GetAgentRevenueInfoResp, err error) { - userID, err := ctxdata.GetUidFromCtx(l.ctx) + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理奖励, %v", err) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息, %v", err) + } + userID := claims.UserId + userType := claims.UserType + if userType == model.UserTypeTemp { + return &types.GetAgentRevenueInfoResp{ + Balance: 0, + TotalEarnings: 0, + FrozenBalance: 0, + DirectPush: types.DirectPushReport{ + TotalCommission: 0, + TotalReport: 0, + Today: types.TimeRangeReport{}, + Last7D: types.TimeRangeReport{}, + Last30D: types.TimeRangeReport{}, + }, + ActiveReward: types.ActiveReward{ + TotalReward: 0, + Today: types.ActiveRewardData{}, + Last7D: types.ActiveRewardData{}, + Last30D: types.ActiveRewardData{}, + }, + }, nil } agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) if err != nil { diff --git a/app/main/api/internal/logic/query/queryservicelogic.go b/app/main/api/internal/logic/query/queryservicelogic.go index a92fb94..4a2f6db 100644 --- a/app/main/api/internal/logic/query/queryservicelogic.go +++ b/app/main/api/internal/logic/query/queryservicelogic.go @@ -8,7 +8,6 @@ import ( "time" "tydata-server/app/main/api/internal/service" "tydata-server/common/ctxdata" - jwtx "tydata-server/common/jwt" "tydata-server/common/xerr" "tydata-server/pkg/lzkit/crypto" "tydata-server/pkg/lzkit/validator" @@ -125,8 +124,8 @@ func (l *QueryServiceLogic) ProcessMarriageLogic(req *types.QueryServiceReq) (*t if cacheDataErr != nil { return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -186,8 +185,8 @@ func (l *QueryServiceLogic) ProcessHomeServiceLogic(req *types.QueryServiceReq) return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -247,8 +246,8 @@ func (l *QueryServiceLogic) ProcessRiskAssessmentLogic(req *types.QueryServiceRe return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -307,8 +306,8 @@ func (l *QueryServiceLogic) ProcessCompanyInfoLogic(req *types.QueryServiceReq) return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -368,8 +367,8 @@ func (l *QueryServiceLogic) ProcessRentalInfoLogic(req *types.QueryServiceReq) ( return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -429,8 +428,8 @@ func (l *QueryServiceLogic) ProcessPreLoanBackgroundCheckLogic(req *types.QueryS return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -489,8 +488,8 @@ func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceR return nil, cacheDataErr } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -1393,30 +1392,32 @@ func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product str // 3. 其他情况返回未登录错误 func (l *QueryServiceLogic) GetOrCreateUser() (int64, error) { // 尝试获取用户ID - userID, err := ctxdata.GetUidFromCtx(l.ctx) - if err == nil { - return userID, nil // 已有用户ID,直接返回 - } - - // 如果不是未登录错误,说明是其他错误,直接返回 - if !ctxdata.IsNoUserIdError(err) { + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) + if err != nil { return 0, err } + userID := claims.UserId + return userID, nil - // 检查是否是代理查询或APP请求 - isAgentQuery := false - if agentID, ok := l.ctx.Value("agentIdentifier").(string); ok && agentID != "" { - isAgentQuery = true - } - if app, ok := l.ctx.Value("app").(bool); ok && app { - isAgentQuery = true - } + // // 如果不是未登录错误,说明是其他错误,直接返回 + // if !ctxdata.IsNoUserIdError(err) { + // return 0, err + // } - // 如果不是代理查询或APP请求,返回未登录错误 - if !isAgentQuery { - return 0, ctxdata.ErrNoUserIdInCtx - } + // // 检查是否是代理查询或APP请求 + // isAgentQuery := false + // if agentID, ok := l.ctx.Value("agentIdentifier").(string); ok && agentID != "" { + // isAgentQuery = true + // } + // if app, ok := l.ctx.Value("app").(bool); ok && app { + // isAgentQuery = true + // } - // 创建新用户 - return l.svcCtx.UserService.RegisterUUIDUser(l.ctx) + // // 如果不是代理查询或APP请求,返回未登录错误 + // if !isAgentQuery { + // return 0, ctxdata.ErrNoUserIdInCtx + // } + + // // 创建新用户 + // return l.svcCtx.UserService.RegisterUUIDUser(l.ctx) } diff --git a/app/main/api/internal/logic/user/agentmobilecodeloginlogic.go b/app/main/api/internal/logic/user/agentmobilecodeloginlogic.go deleted file mode 100644 index 2ba1db6..0000000 --- a/app/main/api/internal/logic/user/agentmobilecodeloginlogic.go +++ /dev/null @@ -1,99 +0,0 @@ -package user - -import ( - "context" - "database/sql" - "fmt" - "time" - "tydata-server/app/main/api/internal/svc" - "tydata-server/app/main/api/internal/types" - "tydata-server/app/main/model" - jwtx "tydata-server/common/jwt" - "tydata-server/common/xerr" - "tydata-server/pkg/lzkit/crypto" - - "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/stores/redis" - "github.com/zeromicro/go-zero/core/stores/sqlx" - - "github.com/zeromicro/go-zero/core/logx" -) - -type AgentMobileCodeLoginLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewAgentMobileCodeLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AgentMobileCodeLoginLogic { - return &AgentMobileCodeLoginLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *AgentMobileCodeLoginLogic) AgentMobileCodeLogin(req *types.MobileCodeLoginReq) (resp *types.MobileCodeLoginResp, err error) { - secretKey := l.svcCtx.Config.Encrypt.SecretKey - encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err) - } - // 检查手机号是否在一分钟内已发送过验证码 - redisKey := fmt.Sprintf("%s:%s", "query", encryptedMobile) - cacheCode, err := l.svcCtx.Redis.Get(redisKey) - if err != nil { - if errors.Is(err, redis.Nil) { - return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机登录, 验证码过期") - } - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取验证码redis缓存失败, err: %+v", err) - } - if cacheCode != req.Code { - return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确") - } - - user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) - if findUserErr != nil && findUserErr != model.ErrNotFound { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile: %s, err: %+v", encryptedMobile, err) - } - if user == nil { - user = &model.User{Mobile: sql.NullString{String: encryptedMobile, Valid: true}} - // if len(main.Nickname) == 0 { - // main.Nickname = "" - // } - if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { - insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user) - if userInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, err) - } - lastId, lastInsertIdErr := insertResult.LastInsertId() - if lastInsertIdErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user) - } - user.Id = lastId - - userAuth := new(model.UserAuth) - userAuth.UserId = lastId - userAuth.AuthKey = encryptedMobile - userAuth.AuthType = model.UserAuthTypeH5Mobile - if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr) - } - return nil - }); transErr != nil { - return nil, transErr - } - } - token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id) - } - - // 获取当前时间戳 - now := time.Now().Unix() - return &types.MobileCodeLoginResp{ - AccessToken: token, - AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, - RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, - }, nil -} diff --git a/app/main/api/internal/logic/user/bindmobilelogic.go b/app/main/api/internal/logic/user/bindmobilelogic.go index 28e1fd4..7096bcf 100644 --- a/app/main/api/internal/logic/user/bindmobilelogic.go +++ b/app/main/api/internal/logic/user/bindmobilelogic.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "fmt" + "time" "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" @@ -15,7 +16,6 @@ import ( "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/redis" - "github.com/zeromicro/go-zero/core/stores/sqlx" ) type BindMobileLogic struct { @@ -33,22 +33,15 @@ func NewBindMobileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindMo } func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.BindMobileResp, err error) { - userID, getUserIdErr := ctxdata.GetUidFromCtx(l.ctx) - if getUserIdErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, %v", getUserIdErr) + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) + if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, %v", err) } secretKey := l.svcCtx.Config.Encrypt.SecretKey encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 加密手机号失败: %v", err) } - user, err := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) - if err != nil && !errors.Is(err, model.ErrNotFound) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err) - } - if user != nil { - return nil, errors.Wrapf(xerr.NewErrMsg("该手机号已绑定"), "绑定手机号, %v", err) - } // 检查手机号是否在一分钟内已发送过验证码 redisKey := fmt.Sprintf("%s:%s", "bindMobile", encryptedMobile) cacheCode, err := l.svcCtx.Redis.Get(redisKey) @@ -61,44 +54,38 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind if cacheCode != req.Code { return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", encryptedMobile) } - - userModel, err := l.svcCtx.UserModel.FindOne(l.ctx, userID) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err) - } - if userModel.Mobile.Valid && userModel.Mobile.String != "" { - return nil, errors.Wrapf(xerr.NewErrMsg("账号已绑定手机号,无法再次绑定"), "绑定手机号, %v", err) - } - userAuthModel, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, userID, model.UserAuthTypeH5Mobile) + var userID int64 + user, err := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) if err != nil && !errors.Is(err, model.ErrNotFound) { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err) } - if userAuthModel != nil { - return nil, errors.Wrapf(xerr.NewErrMsg("账号已绑定手机号,无法再次绑定"), "绑定手机号, %v", err) + if user != nil { + // 进行平台绑定 + if claims != nil { + if claims.UserType == model.UserTypeTemp { + err = l.svcCtx.UserService.TempUserBindUser(l.ctx, nil, user.Id) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 临时用户绑定用户失败: %+v", err) + } + } + } + userID = user.Id + } else { + // 创建账号,并绑定手机号 + userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 注册用户失败: %+v", err) + } } - var userAuth model.UserAuth - userAuth.UserId = userID - userAuth.AuthType = model.UserAuthTypeH5Mobile - userAuth.AuthKey = encryptedMobile - transErr := l.svcCtx.UserAuthModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { - _, err = l.svcCtx.UserAuthModel.Insert(ctx, session, &userAuth) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err) - } - userModel.Mobile = sql.NullString{ - String: encryptedMobile, - Valid: true, - } - _, err = l.svcCtx.UserModel.Update(l.ctx, session, userModel) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err) - } - return nil - }) - if transErr != nil { - return nil, transErr + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 生成token失败: %+v", err) } - - return &types.BindMobileResp{}, nil + now := time.Now().Unix() + return &types.BindMobileResp{ + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil } diff --git a/app/main/api/internal/logic/user/detaillogic.go b/app/main/api/internal/logic/user/detaillogic.go index 7c76df9..984567e 100644 --- a/app/main/api/internal/logic/user/detaillogic.go +++ b/app/main/api/internal/logic/user/detaillogic.go @@ -30,10 +30,23 @@ func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DetailLogi } func (l *DetailLogic) Detail() (resp *types.UserInfoResp, err error) { - userID, err := ctxdata.GetUidFromCtx(l.ctx) + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err) } + + userID := claims.UserId + userType := claims.UserType + if userType == model.UserTypeTemp { + return &types.UserInfoResp{ + UserInfo: types.User{ + Id: userID, + UserType: userType, + Mobile: "", + NickName: "", + }, + }, nil + } user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID) if err != nil { if errors.Is(err, model.ErrNotFound) { @@ -46,12 +59,15 @@ func (l *DetailLogic) Detail() (resp *types.UserInfoResp, err error) { if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, 用户信息结构体复制失败, %v", err) } + if user.Mobile.Valid { userInfo.Mobile, err = crypto.DecryptMobile(user.Mobile.String, l.svcCtx.Config.Encrypt.SecretKey) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, 解密手机号失败, %v", err) } } + userInfo.UserType = claims.UserType + return &types.UserInfoResp{ UserInfo: userInfo, }, nil diff --git a/app/main/api/internal/logic/user/gettokenlogic.go b/app/main/api/internal/logic/user/gettokenlogic.go index 8c76840..a95ebda 100644 --- a/app/main/api/internal/logic/user/gettokenlogic.go +++ b/app/main/api/internal/logic/user/gettokenlogic.go @@ -4,7 +4,6 @@ import ( "context" "time" "tydata-server/common/ctxdata" - jwtx "tydata-server/common/jwt" "tydata-server/common/xerr" "github.com/pkg/errors" @@ -32,11 +31,11 @@ func NewGetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetToken func (l *GetTokenLogic) GetToken() (resp *types.MobileCodeLoginResp, err error) { userID, err := ctxdata.GetUidFromCtx(l.ctx) if err != nil { - return nil, errors.Wrapf(xerr.NewErrMsg(""), "用户信息, %v", err) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err) } - token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %d", userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err) } // 获取当前时间戳 now := time.Now().Unix() diff --git a/app/main/api/internal/logic/user/mobilecodeloginlogic.go b/app/main/api/internal/logic/user/mobilecodeloginlogic.go index 643a8e7..d543e33 100644 --- a/app/main/api/internal/logic/user/mobilecodeloginlogic.go +++ b/app/main/api/internal/logic/user/mobilecodeloginlogic.go @@ -8,13 +8,11 @@ import ( "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" "tydata-server/app/main/model" - jwtx "tydata-server/common/jwt" "tydata-server/common/xerr" "tydata-server/pkg/lzkit/crypto" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/redis" - "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/logx" ) @@ -53,42 +51,22 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", encryptedMobile) } } - + var userID int64 user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) if findUserErr != nil && findUserErr != model.ErrNotFound { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile: %s, err: %+v", encryptedMobile, err) } if user == nil { - user = &model.User{Mobile: sql.NullString{String: encryptedMobile, Valid: true}} - // if len(main.Nickname) == 0 { - // main.Nickname = encryptedMobile - // } - if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { - insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user) - if userInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, err) - } - lastId, lastInsertIdErr := insertResult.LastInsertId() - if lastInsertIdErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user) - } - user.Id = lastId - - userAuth := new(model.UserAuth) - userAuth.UserId = lastId - userAuth.AuthKey = encryptedMobile - userAuth.AuthType = model.UserAuthTypeAppMobile - if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr) - } - return nil - }); transErr != nil { - return nil, transErr + userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 注册用户失败: %+v", err) } + } else { + userID = user.Id } - token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID) } // 获取当前时间戳 diff --git a/app/main/api/internal/logic/user/mobileloginlogic.go b/app/main/api/internal/logic/user/mobileloginlogic.go deleted file mode 100644 index dbfa4ac..0000000 --- a/app/main/api/internal/logic/user/mobileloginlogic.go +++ /dev/null @@ -1,65 +0,0 @@ -package user - -import ( - "context" - "database/sql" - "time" - "tydata-server/app/main/model" - jwtx "tydata-server/common/jwt" - "tydata-server/common/tool" - "tydata-server/common/xerr" - "tydata-server/pkg/lzkit/crypto" - "tydata-server/pkg/lzkit/lzUtils" - - "github.com/pkg/errors" - - "tydata-server/app/main/api/internal/svc" - "tydata-server/app/main/api/internal/types" - - "github.com/zeromicro/go-zero/core/logx" -) - -type MobileLoginLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewMobileLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MobileLoginLogic { - return &MobileLoginLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *MobileLoginLogic) MobileLogin(req *types.MobileLoginReq) (resp *types.MobileCodeLoginResp, err error) { - secretKey := l.svcCtx.Config.Encrypt.SecretKey - encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err) - } - user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) - if findUserErr != nil && findUserErr != model.ErrNotFound { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile%s, err: %+v", encryptedMobile, err) - } - if user == nil { - return nil, errors.Wrapf(xerr.NewErrMsg("手机号码未注册"), "手机登录, 手机号未注册:%s", encryptedMobile) - } - if !(tool.Md5ByString(req.Password) == lzUtils.NullStringToString(user.Password)) { - return nil, errors.Wrapf(xerr.NewErrMsg("密码不正确"), "手机登录, 密码匹配不正确%s", encryptedMobile) - } - - token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id) - } - - // 获取当前时间戳 - now := time.Now().Unix() - return &types.MobileCodeLoginResp{ - AccessToken: token, - AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, - RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, - }, nil -} diff --git a/app/main/api/internal/logic/user/registerlogic.go b/app/main/api/internal/logic/user/registerlogic.go deleted file mode 100644 index 894c5ca..0000000 --- a/app/main/api/internal/logic/user/registerlogic.go +++ /dev/null @@ -1,106 +0,0 @@ -package user - -import ( - "context" - "database/sql" - "fmt" - "time" - "tydata-server/app/main/api/internal/svc" - "tydata-server/app/main/api/internal/types" - "tydata-server/app/main/model" - jwtx "tydata-server/common/jwt" - "tydata-server/common/tool" - "tydata-server/common/xerr" - "tydata-server/pkg/lzkit/crypto" - "tydata-server/pkg/lzkit/lzUtils" - - "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/stores/redis" - "github.com/zeromicro/go-zero/core/stores/sqlx" - - "github.com/zeromicro/go-zero/core/logx" -) - -type RegisterLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic { - return &RegisterLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *RegisterLogic) Register(req *types.RegisterReq) (resp *types.RegisterResp, err error) { - secretKey := l.svcCtx.Config.Encrypt.SecretKey - encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机注册, 加密手机号失败: %+v", err) - } - // 检查手机号是否在一分钟内已发送过验证码 - redisKey := fmt.Sprintf("%s:%s", "register", encryptedMobile) - cacheCode, err := l.svcCtx.Redis.Get(redisKey) - if err != nil { - if errors.Is(err, redis.Nil) { - return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机注册, 验证码过期: %s", encryptedMobile) - } - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err) - } - if cacheCode != req.Code { - return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机注册, 验证码不正确: %s", encryptedMobile) - } - hasUser, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) - if findUserErr != nil && findUserErr != model.ErrNotFound { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 读取数据库获取用户失败, mobile%s, err: %+v", encryptedMobile, err) - } - if hasUser != nil { - return nil, errors.Wrapf(xerr.NewErrMsg("该手机号码已注册"), "手机注册, 手机号码已注册, mobile:%s", encryptedMobile) - } - var userId int64 - if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { - user := new(model.User) - user.Mobile = sql.NullString{String: encryptedMobile, Valid: true} - // if len(main.Nickname) == 0 { - // main.Nickname = encryptedMobile - // } - if len(req.Password) > 0 { - user.Password = lzUtils.StringToNullString(tool.Md5ByString(req.Password)) - } - insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user) - if userInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, err) - } - lastId, lastInsertIdErr := insertResult.LastInsertId() - if lastInsertIdErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user) - } - userId = lastId - - userAuth := new(model.UserAuth) - userAuth.UserId = lastId - userAuth.AuthKey = encryptedMobile - userAuth.AuthType = model.UserAuthTypeAppMobile - if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr) - } - return nil - }); transErr != nil { - return nil, transErr - } - - token, generaErr := jwtx.GenerateJwtToken(userId, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if generaErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机注册, 生成jwt token失败, userid: %d, err:%+v", userId, generaErr) - } - // 获取当前时间戳 - now := time.Now().Unix() - return &types.RegisterResp{ - AccessToken: token, - AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, - RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, - }, nil -} diff --git a/app/main/api/internal/logic/user/wxh5authlogic.go b/app/main/api/internal/logic/user/wxh5authlogic.go index b39ada2..e51d309 100644 --- a/app/main/api/internal/logic/user/wxh5authlogic.go +++ b/app/main/api/internal/logic/user/wxh5authlogic.go @@ -8,11 +8,9 @@ import ( "net/http" "time" "tydata-server/app/main/model" - jwtx "tydata-server/common/jwt" "tydata-server/common/xerr" "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/stores/sqlx" "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" @@ -40,60 +38,51 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err) } - if accessTokenResp.AccessToken == "" || accessTokenResp.Openid == "" { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token为空: %v", accessTokenResp) - } + // Step 2: 查找用户授权信息 - userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5, accessTokenResp.Openid) + userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid) if findErr != nil && !errors.Is(findErr, model.ErrNotFound) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询用户授权失败,findErr: %v", findErr) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户授权失败: %v", findErr) } - // Step 3: 查找或创建用户 - var user *model.User + // Step 3: 处理用户信息 + var userID int64 if userAuth != nil { - // 授权信息存在,查找用户 - userModel, findUserErr := l.svcCtx.UserModel.FindOne(l.ctx, userAuth.UserId) - if findUserErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询用户失败,userId: %v", findUserErr) - } - user = userModel + // 已存在用户,直接登录 + userID = userAuth.UserId } else { - // 授权信息不存在,创建新用户 - user = &model.User{} - if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(context context.Context, session sqlx.Session) error { - // 插入数据库 - insertResult, insertErr := l.svcCtx.UserModel.Insert(l.ctx, session, user) - if insertErr != nil { - return errors.Wrapf(insertErr, "创建新用户失败,openid: %s", accessTokenResp.Openid) - } - // 获取插入后生成的 main.Id - lastInsertId, lastInsertIdErr := insertResult.LastInsertId() - if lastInsertIdErr != nil { - return errors.Wrapf(lastInsertIdErr, "获取新用户ID失败,openid: %s", accessTokenResp.Openid) - } - user.Id = lastInsertId - // 创建用户授权信息 - userAuth = &model.UserAuth{ - UserId: user.Id, + // 检查临时用户表 + userTemp, err := l.svcCtx.UserTempModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户临时信息失败: %v", err) + } + + if userTemp == nil { + // 创建临时用户记录 + userTemp = &model.UserTemp{ + AuthType: model.UserAuthTypeWxh5OpenID, AuthKey: accessTokenResp.Openid, - AuthType: model.UserAuthTypeWxh5, // 微信小程序 } - if _, insertUserAuthErr := l.svcCtx.UserAuthModel.Insert(l.ctx, session, userAuth); insertUserAuthErr != nil { - return errors.Wrapf(insertUserAuthErr, "创建用户授权失败,openid: %s", accessTokenResp.Openid) + result, err := l.svcCtx.UserTempModel.Insert(l.ctx, nil, userTemp) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建临时用户信息失败: %v", err) } - return nil - }); transErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建新用户事务失败: %v", transErr) + userID, err = result.LastInsertId() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取新创建的临时用户ID失败: %v", err) + } + } else { + userID = userTemp.Id } } // Step 4: 生成JWT Token - token, genErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire) - if genErr != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成JWT token失败: %v", genErr) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err) } + // Step 5: 返回登录结果 now := time.Now().Unix() return &types.WXH5AuthResp{ AccessToken: token, @@ -130,9 +119,9 @@ func (l *WxH5AuthLogic) GetAccessToken(code string) (*AccessTokenResp, error) { return nil, err } - //if accessTokenResp.AccessToken == "" { - // return nil, errors.New("accessTokenResp.AccessToken为空") - //} + if accessTokenResp.AccessToken == "" || accessTokenResp.Openid == "" { + return nil, errors.New("accessTokenResp.AccessToken为空") + } return &accessTokenResp, nil } diff --git a/app/main/api/internal/middleware/authinterceptormiddleware.go b/app/main/api/internal/middleware/authinterceptormiddleware.go index d7703bc..5c210c5 100644 --- a/app/main/api/internal/middleware/authinterceptormiddleware.go +++ b/app/main/api/internal/middleware/authinterceptormiddleware.go @@ -2,12 +2,9 @@ package middleware import ( "context" - "encoding/json" - "fmt" "net/http" "tydata-server/app/main/api/internal/config" - "tydata-server/common/ctxdata" jwtx "tydata-server/common/jwt" "tydata-server/common/xerr" @@ -42,17 +39,14 @@ func (m *AuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFu } // 解析JWT令牌 - userId, err := jwtx.ParseJwtToken(authHeader, m.Config.JwtAuth.AccessSecret) + claims, err := jwtx.ParseJwtToken(authHeader, m.Config.JwtAuth.AccessSecret) if err != nil { // JWT解析失败,返回401错误 httpx.Error(w, errors.Wrapf(xerr.NewErrCode(ErrCodeUnauthorized), "token解析失败: %v", err)) return } - // 将用户ID转换为json.Number类型后添加到请求上下文 - userIdStr := fmt.Sprintf("%d", userId) - userIdJsonNum := json.Number(userIdStr) - ctx := context.WithValue(r.Context(), ctxdata.CtxKeyJwtUserId, userIdJsonNum) + ctx := context.WithValue(r.Context(), jwtx.ExtraKey, claims) // 使用新的上下文继续处理请求 next(w, r.WithContext(ctx)) diff --git a/app/main/api/internal/middleware/sourceinterceptormiddleware.go b/app/main/api/internal/middleware/global_sourceinterceptor_middleware.go similarity index 53% rename from app/main/api/internal/middleware/sourceinterceptormiddleware.go rename to app/main/api/internal/middleware/global_sourceinterceptor_middleware.go index 747f848..c7197b3 100644 --- a/app/main/api/internal/middleware/sourceinterceptormiddleware.go +++ b/app/main/api/internal/middleware/global_sourceinterceptor_middleware.go @@ -6,28 +6,16 @@ import ( ) const ( - BrandKey = "X-Brand" PlatformKey = "X-Platform" ) -type SourceInterceptorMiddleware struct { -} - -func NewSourceInterceptorMiddleware() *SourceInterceptorMiddleware { - return &SourceInterceptorMiddleware{} -} - -func (m *SourceInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { +func GlobalSourceInterceptor(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 获取请求头 X-Brand 和 X-Platform 的值 - brand := r.Header.Get(BrandKey) + // 获取请求头 X-Platform 的值 platform := r.Header.Get(PlatformKey) // 将值放入新的 context 中 ctx := r.Context() - if brand != "" { - ctx = context.WithValue(ctx, "brand", brand) - } if platform != "" { ctx = context.WithValue(ctx, "platform", platform) } diff --git a/app/main/api/internal/middleware/userauthinterceptormiddleware.go b/app/main/api/internal/middleware/userauthinterceptormiddleware.go new file mode 100644 index 0000000..439fc8e --- /dev/null +++ b/app/main/api/internal/middleware/userauthinterceptormiddleware.go @@ -0,0 +1,33 @@ +package middleware + +import ( + "net/http" + "tydata-server/app/main/model" + "tydata-server/common/ctxdata" + "tydata-server/common/xerr" + + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/rest/httpx" +) + +type UserAuthInterceptorMiddleware struct { +} + +func NewUserAuthInterceptorMiddleware() *UserAuthInterceptorMiddleware { + return &UserAuthInterceptorMiddleware{} +} + +func (m *UserAuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + claims, err := ctxdata.GetClaimsFromCtx(r.Context()) + if err != nil { + httpx.Error(w, errors.Wrapf(xerr.NewErrCode(ErrCodeUnauthorized), "token解析失败: %v", err)) + return + } + if claims.UserType == model.UserTypeTemp { + httpx.Error(w, errors.Wrapf(xerr.NewErrCode(xerr.USER_NEED_BIND_MOBILE), "token解析失败: %v", err)) + return + } + next(w, r) + } +} diff --git a/app/main/api/internal/service/alipayService.go b/app/main/api/internal/service/alipayService.go index 1e9a89b..1781226 100644 --- a/app/main/api/internal/service/alipayService.go +++ b/app/main/api/internal/service/alipayService.go @@ -10,6 +10,7 @@ import ( "sync/atomic" "time" "tydata-server/app/main/api/internal/config" + "tydata-server/app/main/model" "tydata-server/pkg/lzkit/lzUtils" "github.com/smartwalle/alipay/v3" @@ -104,10 +105,10 @@ func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, s return "", fmt.Errorf("无的支付平台: %s", platform) } switch platform { - case "app": + case model.PlatformApp: // 调用App支付的创建方法 return a.CreateAlipayAppOrder(amount, subject, outTradeNo) - case "h5": + case model.PlatformH5: // 调用H5支付的创建方法,并传入 returnUrl return a.CreateAlipayH5Order(amount, subject, outTradeNo) default: diff --git a/app/main/api/internal/service/userService.go b/app/main/api/internal/service/userService.go index f5c7bab..ab8f050 100644 --- a/app/main/api/internal/service/userService.go +++ b/app/main/api/internal/service/userService.go @@ -2,22 +2,34 @@ package service import ( "context" + "database/sql" + "tydata-server/app/main/api/internal/config" "tydata-server/app/main/model" + "tydata-server/common/ctxdata" + jwtx "tydata-server/common/jwt" + "tydata-server/common/xerr" "github.com/google/uuid" + "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/sqlx" ) type UserService struct { + Config *config.Config userModel model.UserModel userAuthModel model.UserAuthModel + userTempModel model.UserTempModel + agentModel model.AgentModel } // NewUserService 创建UserService实例 -func NewUserService(userModel model.UserModel, userAuthModel model.UserAuthModel) *UserService { +func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, userTempModel model.UserTempModel, agentModel model.AgentModel) *UserService { return &UserService{ + Config: config, userModel: userModel, userAuthModel: userAuthModel, + userTempModel: userTempModel, + agentModel: agentModel, } } @@ -63,3 +75,217 @@ func (s *UserService) RegisterUUIDUser(ctx context.Context) (int64, error) { return userId, nil } + +// generalUserToken 生成用户token +func (s *UserService) GeneralUserToken(ctx context.Context, userID int64) (string, error) { + platform, err := ctxdata.GetPlatformFromCtx(ctx) + if err != nil { + return "", err + } + + var isAgent int64 + var agentID int64 + var userType int64 + user, err := s.userModel.FindOne(ctx, userID) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return "", err + } + if user != nil { + userID = user.Id + userType = model.UserTypeNormal + agent, err := s.agentModel.FindOneByUserId(ctx, userID) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return "", err + } + if agent != nil { + agentID = agent.Id + isAgent = model.AgentStatusYes + } + } else { + userTemp, err := s.userTempModel.FindOne(ctx, userID) + if err != nil { + return "", err + } + if userTemp != nil { + userID = userTemp.Id + userType = model.UserTypeTemp + } + } + token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{ + UserId: userID, + AgentId: agentID, + Platform: platform, + UserType: userType, + IsAgent: isAgent, + }, s.Config.JwtAuth.AccessSecret, s.Config.JwtAuth.AccessExpire) + if generaErr != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %d", userID) + } + return token, nil +} + +// RegisterUser 注册用户,返回用户ID +// 传入手机号,自动注册,如果ctx存在临时用户则临时用户转为正式用户 +func (s *UserService) RegisterUser(ctx context.Context, mobile string) (int64, error) { + claims, err := ctxdata.GetClaimsFromCtx(ctx) + if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { + return 0, err + } + user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true}) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return 0, err + } + if user != nil { + return 0, errors.New("用户已注册") + } + // 普通注册 + if claims == nil { + var userId int64 + err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { + user := &model.User{ + Mobile: sql.NullString{String: mobile, Valid: true}, + } + result, err := s.userModel.Insert(ctx, session, user) + if err != nil { + return err + } + userId, err = result.LastInsertId() + if err != nil { + return err + } + s.userAuthModel.Insert(ctx, session, &model.UserAuth{ + UserId: userId, + AuthType: model.UserAuthTypeMobile, + AuthKey: mobile, + }) + return nil + }) + if err != nil { + return 0, err + } + return userId, nil + } + + // 双重判断是否已经注册 + if claims.UserType == model.UserTypeNormal { + return 0, errors.New("用户已注册") + } + var userId int64 + // 临时转正式注册 + err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { + user := &model.User{ + Mobile: sql.NullString{String: mobile, Valid: true}, + } + result, err := s.userModel.Insert(ctx, session, user) + if err != nil { + return err + } + userId, err = result.LastInsertId() + if err != nil { + return err + } + _, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{ + UserId: userId, + AuthType: model.UserAuthTypeMobile, + AuthKey: mobile, + }) + if err != nil { + return err + } + err = s.TempUserBindUser(ctx, session, userId) + if err != nil { + return err + } + return nil + }) + if err != nil { + return 0, err + } + return userId, nil +} + +// TempUserBindUser 临时用户绑定用户 +func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID int64) error { + claims, err := ctxdata.GetClaimsFromCtx(ctx) + if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { + return err + } + + if claims == nil || claims.UserType != model.UserTypeTemp { + return errors.New("无临时用户") + } + + userTemp, err := s.userTempModel.FindOne(ctx, claims.UserId) + if err != nil { + return err + } + + userAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, userTemp.AuthType, userTemp.AuthKey) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return err + } + if userAuth != nil { + return errors.New("临时用户已注册") + } + + if session == nil { + err := s.userAuthModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { + _, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{ + UserId: normalUserID, + AuthType: userTemp.AuthType, + AuthKey: userTemp.AuthKey, + }) + if err != nil { + return err + } + err = s.userTempModel.DeleteSoft(ctx, session, userTemp) + if err != nil { + return err + } + return nil + }) + if err != nil { + return err + } + return nil + } else { + _, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{ + UserId: normalUserID, + AuthType: userTemp.AuthType, + AuthKey: userTemp.AuthKey, + }) + if err != nil { + return err + } + err = s.userTempModel.DeleteSoft(ctx, session, userTemp) + if err != nil { + return err + } + return nil + } + +} + +// _bak_RegisterUUIDUser 注册UUID用户,返回用户ID +func (s *UserService) _bak_RegisterUUIDUser(ctx context.Context) error { + // 生成UUID + uuidStr, err := s.GenerateUUIDUserId(ctx) + if err != nil { + return err + } + + err = s.userTempModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { + // 创建用户临时记录 + userTemp := &model.UserTemp{ + AuthType: model.UserAuthTypeUUID, + AuthKey: uuidStr, + } + _, err := s.userTempModel.Insert(ctx, session, userTemp) + return err + }) + if err != nil { + return err + } + + return nil +} diff --git a/app/main/api/internal/service/wechatpayService.go b/app/main/api/internal/service/wechatpayService.go index 7c4a684..7e12517 100644 --- a/app/main/api/internal/service/wechatpayService.go +++ b/app/main/api/internal/service/wechatpayService.go @@ -219,12 +219,12 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64 var err error switch platform { - case "mp-weixin": + case model.PlatformWxMini: userID, getUidErr := ctxdata.GetUidFromCtx(ctx) if getUidErr != nil { return "", getUidErr } - userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMini) + userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMiniOpenID) if findAuthModelErr != nil { return "", findAuthModelErr } @@ -232,12 +232,12 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64 if err != nil { return "", err } - case "h5-weixin": + case model.PlatformWxH5: userID, getUidErr := ctxdata.GetUidFromCtx(ctx) if getUidErr != nil { return "", getUidErr } - userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5) + userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID) if findAuthModelErr != nil { return "", findAuthModelErr } @@ -245,7 +245,7 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64 if err != nil { return "", err } - case "app": + case model.PlatformApp: // 如果是 APP 平台,调用 APP 支付订单创建 prepayData, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo) default: diff --git a/app/main/api/internal/svc/servicecontext.go b/app/main/api/internal/svc/servicecontext.go index 2dbc62e..2318f30 100644 --- a/app/main/api/internal/svc/servicecontext.go +++ b/app/main/api/internal/svc/servicecontext.go @@ -8,7 +8,6 @@ import ( "github.com/hibiken/asynq" "github.com/zeromicro/go-zero/core/logx" - "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/rest" @@ -20,12 +19,13 @@ type ServiceContext struct { Redis *redis.Redis // 中间件 - SourceInterceptor rest.Middleware - AuthInterceptor rest.Middleware + AuthInterceptor rest.Middleware + UserAuthInterceptor rest.Middleware // 用户相关模型 UserModel model.UserModel UserAuthModel model.UserAuthModel + UserTempModel model.UserTempModel // 产品相关模型 ProductModel model.ProductModel @@ -94,185 +94,98 @@ type ServiceContext struct { AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService } -// 用户相关模型初始化 -type userModels struct { - UserModel model.UserModel - UserAuthModel model.UserAuthModel -} +// NewServiceContext 创建服务上下文 +func NewServiceContext(c config.Config) *ServiceContext { + // ============================== 基础设施初始化 ============================== + db := sqlx.NewMysql(c.DataSource) + cacheConf := c.CacheRedis -func initUserModels(db sqlx.SqlConn, redis cache.CacheConf) userModels { - return userModels{ - UserModel: model.NewUserModel(db, redis), - UserAuthModel: model.NewUserAuthModel(db, redis), + // 初始化Redis客户端 + redisConf := redis.RedisConf{ + Host: cacheConf[0].Host, + Pass: cacheConf[0].Pass, + Type: cacheConf[0].Type, } -} + redisClient := redis.MustNewRedis(redisConf) -// 产品相关模型初始化 -type productModels struct { - ProductModel model.ProductModel - FeatureModel model.FeatureModel - ProductFeatureModel model.ProductFeatureModel -} + // ============================== 用户相关模型 ============================== + userModel := model.NewUserModel(db, cacheConf) + userAuthModel := model.NewUserAuthModel(db, cacheConf) + userTempModel := model.NewUserTempModel(db, cacheConf) -func initProductModels(db sqlx.SqlConn, redis cache.CacheConf) productModels { - return productModels{ - ProductModel: model.NewProductModel(db, redis), - FeatureModel: model.NewFeatureModel(db, redis), - ProductFeatureModel: model.NewProductFeatureModel(db, redis), - } -} + // ============================== 产品相关模型 ============================== + productModel := model.NewProductModel(db, cacheConf) + featureModel := model.NewFeatureModel(db, cacheConf) + productFeatureModel := model.NewProductFeatureModel(db, cacheConf) -// 订单相关模型初始化 -type orderModels struct { - OrderModel model.OrderModel - QueryModel model.QueryModel - OrderRefundModel model.OrderRefundModel - QueryCleanupLogModel model.QueryCleanupLogModel - QueryCleanupDetailModel model.QueryCleanupDetailModel - QueryCleanupConfigModel model.QueryCleanupConfigModel -} + // ============================== 订单相关模型 ============================== + orderModel := model.NewOrderModel(db, cacheConf) + queryModel := model.NewQueryModel(db, cacheConf) + orderRefundModel := model.NewOrderRefundModel(db, cacheConf) + queryCleanupLogModel := model.NewQueryCleanupLogModel(db, cacheConf) + queryCleanupDetailModel := model.NewQueryCleanupDetailModel(db, cacheConf) + queryCleanupConfigModel := model.NewQueryCleanupConfigModel(db, cacheConf) -func initOrderModels(db sqlx.SqlConn, redis cache.CacheConf) orderModels { - return orderModels{ - OrderModel: model.NewOrderModel(db, redis), - QueryModel: model.NewQueryModel(db, redis), - OrderRefundModel: model.NewOrderRefundModel(db, redis), - QueryCleanupLogModel: model.NewQueryCleanupLogModel(db, redis), - QueryCleanupDetailModel: model.NewQueryCleanupDetailModel(db, redis), - QueryCleanupConfigModel: model.NewQueryCleanupConfigModel(db, redis), - } -} + // ============================== 代理相关模型 ============================== + agentModel := model.NewAgentModel(db, cacheConf) + agentAuditModel := model.NewAgentAuditModel(db, cacheConf) + agentClosureModel := model.NewAgentClosureModel(db, cacheConf) + agentCommissionModel := model.NewAgentCommissionModel(db, cacheConf) + agentCommissionDeductionModel := model.NewAgentCommissionDeductionModel(db, cacheConf) + agentWalletModel := model.NewAgentWalletModel(db, cacheConf) + agentLinkModel := model.NewAgentLinkModel(db, cacheConf) + agentOrderModel := model.NewAgentOrderModel(db, cacheConf) + agentRewardsModel := model.NewAgentRewardsModel(db, cacheConf) + agentMembershipConfigModel := model.NewAgentMembershipConfigModel(db, cacheConf) + agentMembershipRechargeOrderModel := model.NewAgentMembershipRechargeOrderModel(db, cacheConf) + agentMembershipUserConfigModel := model.NewAgentMembershipUserConfigModel(db, cacheConf) + agentProductConfigModel := model.NewAgentProductConfigModel(db, cacheConf) + agentPlatformDeductionModel := model.NewAgentPlatformDeductionModel(db, cacheConf) + agentActiveStatModel := model.NewAgentActiveStatModel(db, cacheConf) + agentWithdrawalModel := model.NewAgentWithdrawalModel(db, cacheConf) + agentRealNameModel := model.NewAgentRealNameModel(db, cacheConf) -// 代理相关模型初始化 -type agentModels struct { - AgentModel model.AgentModel - AgentAuditModel model.AgentAuditModel - AgentClosureModel model.AgentClosureModel - AgentCommissionModel model.AgentCommissionModel - AgentCommissionDeductionModel model.AgentCommissionDeductionModel - AgentWalletModel model.AgentWalletModel - AgentLinkModel model.AgentLinkModel - AgentOrderModel model.AgentOrderModel - AgentRewardsModel model.AgentRewardsModel - AgentMembershipConfigModel model.AgentMembershipConfigModel - AgentMembershipRechargeOrderModel model.AgentMembershipRechargeOrderModel - AgentMembershipUserConfigModel model.AgentMembershipUserConfigModel - AgentProductConfigModel model.AgentProductConfigModel - AgentPlatformDeductionModel model.AgentPlatformDeductionModel - AgentActiveStatModel model.AgentActiveStatModel - AgentWithdrawalModel model.AgentWithdrawalModel - AgentRealNameModel model.AgentRealNameModel -} + // ============================== 管理后台相关模型 ============================== + adminApiModel := model.NewAdminApiModel(db, cacheConf) + adminMenuModel := model.NewAdminMenuModel(db, cacheConf) + adminRoleModel := model.NewAdminRoleModel(db, cacheConf) + adminRoleApiModel := model.NewAdminRoleApiModel(db, cacheConf) + adminRoleMenuModel := model.NewAdminRoleMenuModel(db, cacheConf) + adminUserModel := model.NewAdminUserModel(db, cacheConf) + adminUserRoleModel := model.NewAdminUserRoleModel(db, cacheConf) + adminDictDataModel := model.NewAdminDictDataModel(db, cacheConf) + adminDictTypeModel := model.NewAdminDictTypeModel(db, cacheConf) + adminPromotionLinkModel := model.NewAdminPromotionLinkModel(db, cacheConf) + adminPromotionLinkStatsTotalModel := model.NewAdminPromotionLinkStatsTotalModel(db, cacheConf) + adminPromotionLinkStatsHistoryModel := model.NewAdminPromotionLinkStatsHistoryModel(db, cacheConf) + adminPromotionOrderModel := model.NewAdminPromotionOrderModel(db, cacheConf) -func initAgentModels(db sqlx.SqlConn, redis cache.CacheConf) agentModels { - return agentModels{ - AgentModel: model.NewAgentModel(db, redis), - AgentAuditModel: model.NewAgentAuditModel(db, redis), - AgentClosureModel: model.NewAgentClosureModel(db, redis), - AgentCommissionModel: model.NewAgentCommissionModel(db, redis), - AgentCommissionDeductionModel: model.NewAgentCommissionDeductionModel(db, redis), - AgentWalletModel: model.NewAgentWalletModel(db, redis), - AgentLinkModel: model.NewAgentLinkModel(db, redis), - AgentOrderModel: model.NewAgentOrderModel(db, redis), - AgentRewardsModel: model.NewAgentRewardsModel(db, redis), - AgentMembershipConfigModel: model.NewAgentMembershipConfigModel(db, redis), - AgentMembershipRechargeOrderModel: model.NewAgentMembershipRechargeOrderModel(db, redis), - AgentMembershipUserConfigModel: model.NewAgentMembershipUserConfigModel(db, redis), - AgentProductConfigModel: model.NewAgentProductConfigModel(db, redis), - AgentPlatformDeductionModel: model.NewAgentPlatformDeductionModel(db, redis), - AgentActiveStatModel: model.NewAgentActiveStatModel(db, redis), - AgentWithdrawalModel: model.NewAgentWithdrawalModel(db, redis), - AgentRealNameModel: model.NewAgentRealNameModel(db, redis), - } -} + // ============================== 其他模型 ============================== + exampleModel := model.NewExampleModel(db, cacheConf) + globalNotificationsModel := model.NewGlobalNotificationsModel(db, cacheConf) -// 管理后台相关模型初始化 -type adminModels struct { - AdminApiModel model.AdminApiModel - AdminMenuModel model.AdminMenuModel - AdminRoleModel model.AdminRoleModel - AdminRoleApiModel model.AdminRoleApiModel - AdminRoleMenuModel model.AdminRoleMenuModel - AdminUserModel model.AdminUserModel - AdminUserRoleModel model.AdminUserRoleModel - AdminDictDataModel model.AdminDictDataModel - AdminDictTypeModel model.AdminDictTypeModel - AdminPromotionLinkModel model.AdminPromotionLinkModel - AdminPromotionLinkStatsTotalModel model.AdminPromotionLinkStatsTotalModel - AdminPromotionLinkStatsHistoryModel model.AdminPromotionLinkStatsHistoryModel - AdminPromotionOrderModel model.AdminPromotionOrderModel -} - -func initAdminModels(db sqlx.SqlConn, redis cache.CacheConf) adminModels { - return adminModels{ - AdminApiModel: model.NewAdminApiModel(db, redis), - AdminMenuModel: model.NewAdminMenuModel(db, redis), - AdminRoleModel: model.NewAdminRoleModel(db, redis), - AdminRoleApiModel: model.NewAdminRoleApiModel(db, redis), - AdminRoleMenuModel: model.NewAdminRoleMenuModel(db, redis), - AdminUserModel: model.NewAdminUserModel(db, redis), - AdminUserRoleModel: model.NewAdminUserRoleModel(db, redis), - AdminDictDataModel: model.NewAdminDictDataModel(db, redis), - AdminDictTypeModel: model.NewAdminDictTypeModel(db, redis), - AdminPromotionLinkModel: model.NewAdminPromotionLinkModel(db, redis), - AdminPromotionLinkStatsTotalModel: model.NewAdminPromotionLinkStatsTotalModel(db, redis), - AdminPromotionLinkStatsHistoryModel: model.NewAdminPromotionLinkStatsHistoryModel(db, redis), - AdminPromotionOrderModel: model.NewAdminPromotionOrderModel(db, redis), - } -} - -// 其他模型初始化 -type otherModels struct { - ExampleModel model.ExampleModel - GlobalNotificationsModel model.GlobalNotificationsModel -} - -func initOtherModels(db sqlx.SqlConn, redis cache.CacheConf) otherModels { - return otherModels{ - ExampleModel: model.NewExampleModel(db, redis), - GlobalNotificationsModel: model.NewGlobalNotificationsModel(db, redis), - } -} - -// 服务初始化 -type services struct { - AlipayService *service.AliPayService - WechatPayService *service.WechatPayService - ApplePayService *service.ApplePayService - WestDexService *service.WestDexService - YushanService *service.YushanService - ApiRequestService *service.ApiRequestService - AsynqServer *asynq.Server - AsynqService *service.AsynqService - VerificationService *service.VerificationService - AgentService *service.AgentService - UserService *service.UserService - DictService *service.DictService - AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService -} - -func initServices(c config.Config, userAuthModel model.UserAuthModel, westDexService *service.WestDexService, - yushanService *service.YushanService, featureModel model.FeatureModel, - productFeatureModel model.ProductFeatureModel, agentModels agentModels, - userModels userModels, adminModels adminModels) services { + // ============================== 第三方服务初始化 ============================== + westDexService := service.NewWestDexService(c) + yushanService := service.NewYushanService(c) + // ============================== 业务服务初始化 ============================== alipayService := service.NewAliPayService(c) -wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey) + wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey) applePayService := service.NewApplePayService(c) apiRequestService := service.NewApiRequestService(c, westDexService, yushanService, featureModel, productFeatureModel) verificationService := service.NewVerificationService(c, westDexService, apiRequestService) asynqService := service.NewAsynqService(c) - agentService := service.NewAgentService(c, agentModels.AgentModel, agentModels.AgentAuditModel, - agentModels.AgentClosureModel, agentModels.AgentCommissionModel, - agentModels.AgentCommissionDeductionModel, agentModels.AgentWalletModel, - agentModels.AgentLinkModel, agentModels.AgentOrderModel, agentModels.AgentRewardsModel, - agentModels.AgentMembershipConfigModel, agentModels.AgentMembershipRechargeOrderModel, - agentModels.AgentMembershipUserConfigModel, agentModels.AgentProductConfigModel, - agentModels.AgentPlatformDeductionModel, agentModels.AgentActiveStatModel, - agentModels.AgentWithdrawalModel) - userService := service.NewUserService(userModels.UserModel, userModels.UserAuthModel) - dictService := service.NewDictService(adminModels.AdminDictTypeModel, adminModels.AdminDictDataModel) - AdminPromotionLinkStatsService := service.NewAdminPromotionLinkStatsService(adminModels.AdminPromotionLinkModel, adminModels.AdminPromotionLinkStatsTotalModel, adminModels.AdminPromotionLinkStatsHistoryModel) + agentService := service.NewAgentService(c, agentModel, agentAuditModel, agentClosureModel, + agentCommissionModel, agentCommissionDeductionModel, agentWalletModel, agentLinkModel, + agentOrderModel, agentRewardsModel, agentMembershipConfigModel, agentMembershipRechargeOrderModel, + agentMembershipUserConfigModel, agentProductConfigModel, agentPlatformDeductionModel, + agentActiveStatModel, agentWithdrawalModel) + userService := service.NewUserService(&c, userModel, userAuthModel, userTempModel, agentModel) + dictService := service.NewDictService(adminDictTypeModel, adminDictDataModel) + adminPromotionLinkStatsService := service.NewAdminPromotionLinkStatsService(adminPromotionLinkModel, + adminPromotionLinkStatsTotalModel, adminPromotionLinkStatsHistoryModel) + + // ============================== 异步任务服务 ============================== asynqServer := asynq.NewServer( asynq.RedisClientOpt{Addr: c.CacheRedis[0].Host, Password: c.CacheRedis[0].Pass}, asynq.Config{ @@ -284,7 +197,70 @@ wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTy }, ) - return services{ + // ============================== 返回服务上下文 ============================== + return &ServiceContext{ + Config: c, + Redis: redisClient, + AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle, + UserAuthInterceptor: middleware.NewUserAuthInterceptorMiddleware().Handle, + + // 用户相关模型 + UserModel: userModel, + UserAuthModel: userAuthModel, + UserTempModel: userTempModel, + + // 产品相关模型 + ProductModel: productModel, + FeatureModel: featureModel, + ProductFeatureModel: productFeatureModel, + + // 订单相关模型 + OrderModel: orderModel, + QueryModel: queryModel, + OrderRefundModel: orderRefundModel, + QueryCleanupLogModel: queryCleanupLogModel, + QueryCleanupDetailModel: queryCleanupDetailModel, + QueryCleanupConfigModel: queryCleanupConfigModel, + + // 代理相关模型 + AgentModel: agentModel, + AgentAuditModel: agentAuditModel, + AgentClosureModel: agentClosureModel, + AgentCommissionModel: agentCommissionModel, + AgentCommissionDeductionModel: agentCommissionDeductionModel, + AgentWalletModel: agentWalletModel, + AgentLinkModel: agentLinkModel, + AgentOrderModel: agentOrderModel, + AgentRewardsModel: agentRewardsModel, + AgentMembershipConfigModel: agentMembershipConfigModel, + AgentMembershipRechargeOrderModel: agentMembershipRechargeOrderModel, + AgentMembershipUserConfigModel: agentMembershipUserConfigModel, + AgentProductConfigModel: agentProductConfigModel, + AgentPlatformDeductionModel: agentPlatformDeductionModel, + AgentActiveStatModel: agentActiveStatModel, + AgentWithdrawalModel: agentWithdrawalModel, + AgentRealNameModel: agentRealNameModel, + + // 管理后台相关模型 + AdminApiModel: adminApiModel, + AdminMenuModel: adminMenuModel, + AdminRoleModel: adminRoleModel, + AdminRoleApiModel: adminRoleApiModel, + AdminRoleMenuModel: adminRoleMenuModel, + AdminUserModel: adminUserModel, + AdminUserRoleModel: adminUserRoleModel, + AdminDictDataModel: adminDictDataModel, + AdminDictTypeModel: adminDictTypeModel, + AdminPromotionLinkModel: adminPromotionLinkModel, + AdminPromotionLinkStatsTotalModel: adminPromotionLinkStatsTotalModel, + AdminPromotionLinkStatsHistoryModel: adminPromotionLinkStatsHistoryModel, + AdminPromotionOrderModel: adminPromotionOrderModel, + + // 其他模型 + ExampleModel: exampleModel, + GlobalNotificationsModel: globalNotificationsModel, + + // 服务 AlipayService: alipayService, WechatPayService: wechatPayService, ApplePayService: applePayService, @@ -297,115 +273,7 @@ wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTy AgentService: agentService, UserService: userService, DictService: dictService, - AdminPromotionLinkStatsService: AdminPromotionLinkStatsService, - } -} - -// NewServiceContext 创建服务上下文 -func NewServiceContext(c config.Config) *ServiceContext { - db := sqlx.NewMysql(c.DataSource) - - // 使用配置中的CacheRedis配置 - cacheConf := c.CacheRedis - - // 初始化Redis客户端(用于异步任务等) - redisConf := redis.RedisConf{ - Host: cacheConf[0].Host, - Pass: cacheConf[0].Pass, - Type: cacheConf[0].Type, - } - redisClient := redis.MustNewRedis(redisConf) - - // 初始化各个模块的模型 - userModels := initUserModels(db, cacheConf) - productModels := initProductModels(db, cacheConf) - orderModels := initOrderModels(db, cacheConf) - agentModels := initAgentModels(db, cacheConf) - adminModels := initAdminModels(db, cacheConf) - otherModels := initOtherModels(db, cacheConf) - - // 初始化第三方服务 - westDexService := service.NewWestDexService(c) - yushanService := service.NewYushanService(c) - - // 初始化所有服务 - services := initServices(c, userModels.UserAuthModel, westDexService, yushanService, - productModels.FeatureModel, productModels.ProductFeatureModel, agentModels, userModels, adminModels) - - return &ServiceContext{ - Config: c, - Redis: redisClient, - SourceInterceptor: middleware.NewSourceInterceptorMiddleware().Handle, - AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle, - - // 用户相关模型 - UserModel: userModels.UserModel, - UserAuthModel: userModels.UserAuthModel, - - // 产品相关模型 - ProductModel: productModels.ProductModel, - FeatureModel: productModels.FeatureModel, - ProductFeatureModel: productModels.ProductFeatureModel, - - // 订单相关模型 - OrderModel: orderModels.OrderModel, - QueryModel: orderModels.QueryModel, - OrderRefundModel: orderModels.OrderRefundModel, - QueryCleanupLogModel: orderModels.QueryCleanupLogModel, - QueryCleanupDetailModel: orderModels.QueryCleanupDetailModel, - QueryCleanupConfigModel: orderModels.QueryCleanupConfigModel, - // 代理相关模型 - AgentModel: agentModels.AgentModel, - AgentAuditModel: agentModels.AgentAuditModel, - AgentClosureModel: agentModels.AgentClosureModel, - AgentCommissionModel: agentModels.AgentCommissionModel, - AgentCommissionDeductionModel: agentModels.AgentCommissionDeductionModel, - AgentWalletModel: agentModels.AgentWalletModel, - AgentLinkModel: agentModels.AgentLinkModel, - AgentOrderModel: agentModels.AgentOrderModel, - AgentRewardsModel: agentModels.AgentRewardsModel, - AgentMembershipConfigModel: agentModels.AgentMembershipConfigModel, - AgentMembershipRechargeOrderModel: agentModels.AgentMembershipRechargeOrderModel, - AgentMembershipUserConfigModel: agentModels.AgentMembershipUserConfigModel, - AgentProductConfigModel: agentModels.AgentProductConfigModel, - AgentPlatformDeductionModel: agentModels.AgentPlatformDeductionModel, - AgentActiveStatModel: agentModels.AgentActiveStatModel, - AgentWithdrawalModel: agentModels.AgentWithdrawalModel, - AgentRealNameModel: agentModels.AgentRealNameModel, - - // 管理后台相关模型 - AdminApiModel: adminModels.AdminApiModel, - AdminMenuModel: adminModels.AdminMenuModel, - AdminRoleModel: adminModels.AdminRoleModel, - AdminRoleApiModel: adminModels.AdminRoleApiModel, - AdminRoleMenuModel: adminModels.AdminRoleMenuModel, - AdminUserModel: adminModels.AdminUserModel, - AdminUserRoleModel: adminModels.AdminUserRoleModel, - AdminDictDataModel: adminModels.AdminDictDataModel, - AdminDictTypeModel: adminModels.AdminDictTypeModel, - AdminPromotionLinkModel: adminModels.AdminPromotionLinkModel, - AdminPromotionLinkStatsTotalModel: adminModels.AdminPromotionLinkStatsTotalModel, - AdminPromotionLinkStatsHistoryModel: adminModels.AdminPromotionLinkStatsHistoryModel, - AdminPromotionOrderModel: adminModels.AdminPromotionOrderModel, - - // 其他模型 - ExampleModel: otherModels.ExampleModel, - GlobalNotificationsModel: otherModels.GlobalNotificationsModel, - - // 服务 - AlipayService: services.AlipayService, - WechatPayService: services.WechatPayService, - ApplePayService: services.ApplePayService, - WestDexService: services.WestDexService, - YushanService: services.YushanService, - ApiRequestService: services.ApiRequestService, - AsynqServer: services.AsynqServer, - AsynqService: services.AsynqService, - VerificationService: services.VerificationService, - AgentService: services.AgentService, - UserService: services.UserService, - DictService: services.DictService, - AdminPromotionLinkStatsService: services.AdminPromotionLinkStatsService, + AdminPromotionLinkStatsService: adminPromotionLinkStatsService, } } diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index ff6e586..6074a04 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -962,6 +962,9 @@ type BindMobileReq struct { } type BindMobileResp struct { + AccessToken string `json:"accessToken"` + AccessExpire int64 `json:"accessExpire"` + RefreshAfter int64 `json:"refreshAfter"` } type Commission struct { @@ -1293,17 +1296,6 @@ type MobileCodeLoginResp struct { RefreshAfter int64 `json:"refreshAfter"` } -type MobileLoginReq struct { - Mobile string `json:"mobile" validate:"required,mobile"` - Password string `json:"password" validate:"required"` -} - -type MobileLoginResp struct { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` -} - type Notification struct { Title string `json:"title"` // 通知标题 Content string `json:"content"` // 通知内容 (富文本) @@ -1596,18 +1588,6 @@ type RecordLinkClickResp struct { Success bool `json:"success"` // 是否成功 } -type RegisterReq struct { - Mobile string `json:"mobile" validate:"required,mobile"` - Password string `json:"password" validate:"required,min=11,max=11,password"` - Code string `json:"code" validate:"required"` -} - -type RegisterResp struct { - AccessToken string `json:"accessToken"` - AccessExpire int64 `json:"accessExpire"` - RefreshAfter int64 `json:"refreshAfter"` -} - type Rewards struct { Type string `json:"type"` Amount float64 `json:"amount"` @@ -1692,6 +1672,7 @@ type User struct { Id int64 `json:"id"` Mobile string `json:"mobile"` NickName string `json:"nickName"` + UserType int64 `json:"userType"` } type UserInfoResp struct { diff --git a/app/main/api/main.go b/app/main/api/main.go index 8fe2455..b866d11 100644 --- a/app/main/api/main.go +++ b/app/main/api/main.go @@ -7,6 +7,7 @@ import ( "os" "tydata-server/app/main/api/internal/config" "tydata-server/app/main/api/internal/handler" + "tydata-server/app/main/api/internal/middleware" "tydata-server/app/main/api/internal/queue" "tydata-server/app/main/api/internal/svc" @@ -55,6 +56,7 @@ func main() { }() server := rest.MustNewServer(c.RestConf) + server.Use(middleware.GlobalSourceInterceptor) defer server.Stop() handler.RegisterHandlers(server, svcContext) diff --git a/app/main/model/userTempModel.go b/app/main/model/userTempModel.go new file mode 100644 index 0000000..bcb7978 --- /dev/null +++ b/app/main/model/userTempModel.go @@ -0,0 +1,27 @@ +package model + +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +var _ UserTempModel = (*customUserTempModel)(nil) + +type ( + // UserTempModel is an interface to be customized, add more methods here, + // and implement the added methods in customUserTempModel. + UserTempModel interface { + userTempModel + } + + customUserTempModel struct { + *defaultUserTempModel + } +) + +// NewUserTempModel returns a model for the database table. +func NewUserTempModel(conn sqlx.SqlConn, c cache.CacheConf) UserTempModel { + return &customUserTempModel{ + defaultUserTempModel: newUserTempModel(conn, c), + } +} diff --git a/app/main/model/userTempModel_gen.go b/app/main/model/userTempModel_gen.go new file mode 100644 index 0000000..bc1a06c --- /dev/null +++ b/app/main/model/userTempModel_gen.go @@ -0,0 +1,407 @@ +// Code generated by goctl. DO NOT EDIT! + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "time" + + "github.com/Masterminds/squirrel" + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" + "tydata-server/common/globalkey" +) + +var ( + userTempFieldNames = builder.RawFieldNames(&UserTemp{}) + userTempRows = strings.Join(userTempFieldNames, ",") + userTempRowsExpectAutoSet = strings.Join(stringx.Remove(userTempFieldNames, "`id`", "`create_time`", "`update_time`"), ",") + userTempRowsWithPlaceHolder = strings.Join(stringx.Remove(userTempFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?" + + cacheTydataUserTempIdPrefix = "cache:tydata:userTemp:id:" + cacheTydataUserTempAuthTypeAuthKeyPrefix = "cache:tydata:userTemp:authType:authKey:" +) + +type ( + userTempModel interface { + Insert(ctx context.Context, session sqlx.Session, data *UserTemp) (sql.Result, error) + FindOne(ctx context.Context, id int64) (*UserTemp, error) + FindOneByAuthTypeAuthKey(ctx context.Context, authType string, authKey string) (*UserTemp, error) + Update(ctx context.Context, session sqlx.Session, data *UserTemp) (sql.Result, error) + UpdateWithVersion(ctx context.Context, session sqlx.Session, data *UserTemp) error + Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error + SelectBuilder() squirrel.SelectBuilder + DeleteSoft(ctx context.Context, session sqlx.Session, data *UserTemp) error + FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error) + FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error) + FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*UserTemp, error) + FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, error) + FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, int64, error) + FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*UserTemp, error) + FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*UserTemp, error) + Delete(ctx context.Context, session sqlx.Session, id int64) error + } + + defaultUserTempModel struct { + sqlc.CachedConn + table string + } + + UserTemp struct { + Id int64 `db:"id"` + AuthKey string `db:"auth_key"` // 平台唯一id + AuthType string `db:"auth_type"` // 平台类型 + CreateTime time.Time `db:"create_time"` + UpdateTime time.Time `db:"update_time"` + DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 + DelState int64 `db:"del_state"` + Version int64 `db:"version"` // 版本号 + } +) + +func newUserTempModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultUserTempModel { + return &defaultUserTempModel{ + CachedConn: sqlc.NewConn(conn, c), + table: "`user_temp`", + } +} + +func (m *defaultUserTempModel) Insert(ctx context.Context, session sqlx.Session, data *UserTemp) (sql.Result, error) { + data.DelState = globalkey.DelStateNo + tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey) + tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, data.Id) + return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, userTempRowsExpectAutoSet) + if session != nil { + return session.ExecCtx(ctx, query, data.AuthKey, data.AuthType, data.DeleteTime, data.DelState, data.Version) + } + return conn.ExecCtx(ctx, query, data.AuthKey, data.AuthType, data.DeleteTime, data.DelState, data.Version) + }, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey) +} + +func (m *defaultUserTempModel) FindOne(ctx context.Context, id int64) (*UserTemp, error) { + tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, id) + var resp UserTemp + err := m.QueryRowCtx(ctx, &resp, tydataUserTempIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error { + query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", userTempRows, m.table) + return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo) + }) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultUserTempModel) FindOneByAuthTypeAuthKey(ctx context.Context, authType string, authKey string) (*UserTemp, error) { + tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, authType, authKey) + var resp UserTemp + err := m.QueryRowIndexCtx(ctx, &resp, tydataUserTempAuthTypeAuthKeyKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { + query := fmt.Sprintf("select %s from %s where `auth_type` = ? and `auth_key` = ? and del_state = ? limit 1", userTempRows, m.table) + if err := conn.QueryRowCtx(ctx, &resp, query, authType, authKey, globalkey.DelStateNo); err != nil { + return nil, err + } + return resp.Id, nil + }, m.queryPrimary) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultUserTempModel) Update(ctx context.Context, session sqlx.Session, newData *UserTemp) (sql.Result, error) { + data, err := m.FindOne(ctx, newData.Id) + if err != nil { + return nil, err + } + tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey) + tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, data.Id) + return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userTempRowsWithPlaceHolder) + if session != nil { + return session.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) + } + return conn.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) + }, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey) +} + +func (m *defaultUserTempModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *UserTemp) error { + + oldVersion := newData.Version + newData.Version += 1 + + var sqlResult sql.Result + var err error + + data, err := m.FindOne(ctx, newData.Id) + if err != nil { + return err + } + tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey) + tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, data.Id) + sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, userTempRowsWithPlaceHolder) + if session != nil { + return session.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) + } + return conn.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) + }, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey) + if err != nil { + return err + } + updateCount, err := sqlResult.RowsAffected() + if err != nil { + return err + } + if updateCount == 0 { + return ErrNoRowsUpdate + } + + return nil +} + +func (m *defaultUserTempModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *UserTemp) error { + data.DelState = globalkey.DelStateYes + data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true} + if err := m.UpdateWithVersion(ctx, session, data); err != nil { + return errors.Wrapf(errors.New("delete soft failed "), "UserTempModel delete err : %+v", err) + } + return nil +} + +func (m *defaultUserTempModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) { + + if len(field) == 0 { + return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field") + } + + builder = builder.Columns("IFNULL(SUM(" + field + "),0)") + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return 0, err + } + + var resp float64 + err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return 0, err + } +} + +func (m *defaultUserTempModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) { + + if len(field) == 0 { + return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field") + } + + builder = builder.Columns("COUNT(" + field + ")") + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return 0, err + } + + var resp int64 + err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return 0, err + } +} + +func (m *defaultUserTempModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*UserTemp, error) { + + builder = builder.Columns(userTempRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql() + if err != nil { + return nil, err + } + + var resp []*UserTemp + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultUserTempModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, error) { + + builder = builder.Columns(userTempRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*UserTemp + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultUserTempModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, int64, error) { + + total, err := m.FindCount(ctx, builder, "id") + if err != nil { + return nil, 0, err + } + + builder = builder.Columns(userTempRows) + + if orderBy == "" { + builder = builder.OrderBy("id DESC") + } else { + builder = builder.OrderBy(orderBy) + } + + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, total, err + } + + var resp []*UserTemp + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, total, nil + default: + return nil, total, err + } +} + +func (m *defaultUserTempModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*UserTemp, error) { + + builder = builder.Columns(userTempRows) + + if preMinId > 0 { + builder = builder.Where(" id < ? ", preMinId) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*UserTemp + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultUserTempModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*UserTemp, error) { + + builder = builder.Columns(userTempRows) + + if preMaxId > 0 { + builder = builder.Where(" id > ? ", preMaxId) + } + + query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql() + if err != nil { + return nil, err + } + + var resp []*UserTemp + err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...) + switch err { + case nil: + return resp, nil + default: + return nil, err + } +} + +func (m *defaultUserTempModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error { + + return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error { + return fn(ctx, session) + }) + +} + +func (m *defaultUserTempModel) SelectBuilder() squirrel.SelectBuilder { + return squirrel.Select().From(m.table) +} +func (m *defaultUserTempModel) Delete(ctx context.Context, session sqlx.Session, id int64) error { + data, err := m.FindOne(ctx, id) + if err != nil { + return err + } + + tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey) + tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, id) + _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + if session != nil { + return session.ExecCtx(ctx, query, id) + } + return conn.ExecCtx(ctx, query, id) + }, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey) + return err +} +func (m *defaultUserTempModel) formatPrimary(primary interface{}) string { + return fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, primary) +} +func (m *defaultUserTempModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error { + query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", userTempRows, m.table) + return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo) +} + +func (m *defaultUserTempModel) tableName() string { + return m.table +} diff --git a/app/main/model/vars.go b/app/main/model/vars.go index 72ebbab..6954bea 100644 --- a/app/main/model/vars.go +++ b/app/main/model/vars.go @@ -9,15 +9,20 @@ import ( var ErrNotFound = sqlx.ErrNotFound var ErrNoRowsUpdate = errors.New("update db no rows change") -var UserAuthTypeAppMobile string = "app_mobile" //平台内部 -var UserAuthTypeAppWechat string = "app_wechat" //微信小程序 -var UserAuthTypeH5Mobile string = "h5_mobile" -var UserAuthTypeWxMini string = "wx_mini" -var UserAuthTypeWxh5 string = "wx_h5" -var UserAuthTypeAgentDirect string = "agent_direct" -var UserAuthTypeAgentPromote string = "agent_promote" +// 平台 +var PlatformWxMini string = "wxmini" +var PlatformWxH5 string = "wxh5" +var PlatformApp string = "app" +var PlatformH5 string = "h5" +var PlatformAdmin string = "admin" + +// 用户授权类型 +var UserAuthTypeMobile string = "mobile" +var UserAuthTypeWxMiniOpenID string = "wxmini_openid" +var UserAuthTypeWxh5OpenID string = "wxh5_openid" var UserAuthTypeUUID string = "uuid" +// 代理扣除类型 var AgentDeductionTypeCost string = "cost" var AgentDeductionTypePricing string = "pricing" @@ -78,3 +83,16 @@ const ( AgentRealNameStatusApproved = "approved" AgentRealNameStatusRejected = "rejected" ) + +// 用户身份类型 +const ( + UserTypeTemp = 0 // 临时用户 + UserTypeNormal = 1 // 正式用户 + UserTypeAdmin = 2 // 管理员 +) + +// 代理状态 +const ( + AgentStatusNo = 0 // 非代理 + AgentStatusYes = 1 // 是代理 +) diff --git a/common/ctxdata/ctxData.go b/common/ctxdata/ctxData.go index 10782f5..c1857fb 100644 --- a/common/ctxdata/ctxData.go +++ b/common/ctxdata/ctxData.go @@ -5,14 +5,16 @@ import ( "encoding/json" "errors" "fmt" + "tydata-server/app/main/model" + jwtx "tydata-server/common/jwt" ) const CtxKeyJwtUserId = "userId" // 定义错误类型 var ( - ErrNoUserIdInCtx = errors.New("上下文中没有用户ID") // 未登录 - ErrInvalidUserId = errors.New("用户ID格式无效") // 数据异常 + ErrNoInCtx = errors.New("上下文中没有相关数据") + ErrInvalidUserId = errors.New("用户ID格式无效") // 数据异常 ) // GetUidFromCtx 从 context 中获取用户 ID @@ -20,7 +22,11 @@ func GetUidFromCtx(ctx context.Context) (int64, error) { // 尝试从上下文中获取 jwtUserId value := ctx.Value(CtxKeyJwtUserId) if value == nil { - return 0, ErrNoUserIdInCtx + claims, err := GetClaimsFromCtx(ctx) + if err != nil { + return 0, err + } + return claims.UserId, nil } // 根据值的类型进行不同处理 @@ -47,12 +53,52 @@ func GetUidFromCtx(ctx context.Context) (int64, error) { } } +func GetClaimsFromCtx(ctx context.Context) (*jwtx.JwtClaims, error) { + value := ctx.Value(jwtx.ExtraKey) + if value == nil { + return nil, ErrNoInCtx + } + + // 首先尝试直接断言为 *jwtx.JwtClaims + if claims, ok := value.(*jwtx.JwtClaims); ok { + return claims, nil + } + + // 如果直接断言失败,尝试从 map[string]interface{} 中解析 + if claimsMap, ok := value.(map[string]interface{}); ok { + return jwtx.MapToJwtClaims(claimsMap) + } + + return nil, ErrNoInCtx +} + // IsNoUserIdError 判断是否是未登录错误 func IsNoUserIdError(err error) bool { - return errors.Is(err, ErrNoUserIdInCtx) + return errors.Is(err, ErrNoInCtx) } // IsInvalidUserIdError 判断是否是用户ID格式错误 func IsInvalidUserIdError(err error) bool { return errors.Is(err, ErrInvalidUserId) } + +// GetPlatformFromCtx 从 context 中获取平台 +func GetPlatformFromCtx(ctx context.Context) (string, error) { + platform, platformOk := ctx.Value("platform").(string) + if !platformOk { + return "", fmt.Errorf("平台不存在: %s", platform) + } + + switch platform { + case model.PlatformWxMini: + return model.PlatformWxMini, nil + case model.PlatformWxH5: + return model.PlatformWxH5, nil + case model.PlatformApp: + return model.PlatformApp, nil + case model.PlatformH5: + return model.PlatformH5, nil + default: + return "", fmt.Errorf("不支持的支付平台: %s", platform) + } +} diff --git a/common/ctxdata/ctxData_test.go b/common/ctxdata/ctxData_test.go deleted file mode 100644 index 6d7fb0e..0000000 --- a/common/ctxdata/ctxData_test.go +++ /dev/null @@ -1,179 +0,0 @@ -package ctxdata - -import ( - "context" - "encoding/json" - "errors" - "testing" -) - -func TestGetUidFromCtx(t *testing.T) { - tests := []struct { - name string - ctxSetup func() context.Context - wantUid int64 - wantError error - }{ - { - name: "正常情况_有效用户ID_json.Number", - ctxSetup: func() context.Context { - return context.WithValue(context.Background(), CtxKeyJwtUserId, json.Number("12345")) - }, - wantUid: 12345, - wantError: nil, - }, - { - name: "正常情况_有效用户ID_int64", - ctxSetup: func() context.Context { - return context.WithValue(context.Background(), CtxKeyJwtUserId, int64(12345)) - }, - wantUid: 12345, - wantError: nil, - }, - { - name: "正常情况_有效用户ID_int", - ctxSetup: func() context.Context { - return context.WithValue(context.Background(), CtxKeyJwtUserId, 12345) - }, - wantUid: 12345, - wantError: nil, - }, - { - name: "正常情况_有效用户ID_float64", - ctxSetup: func() context.Context { - return context.WithValue(context.Background(), CtxKeyJwtUserId, float64(12345)) - }, - wantUid: 12345, - wantError: nil, - }, - { - name: "异常情况_上下文中无用户ID", - ctxSetup: func() context.Context { - return context.Background() - }, - wantUid: 0, - wantError: ErrNoUserIdInCtx, - }, - { - name: "异常情况_用户ID类型错误", - ctxSetup: func() context.Context { - return context.WithValue(context.Background(), CtxKeyJwtUserId, "非数字类型") - }, - wantUid: 0, - wantError: ErrInvalidUserId, - }, - { - name: "异常情况_用户ID无法转换为int64", - ctxSetup: func() context.Context { - return context.WithValue(context.Background(), CtxKeyJwtUserId, json.Number("非数字内容")) - }, - wantUid: 0, - wantError: ErrInvalidUserId, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx := tt.ctxSetup() - gotUid, gotErr := GetUidFromCtx(ctx) - - // 检查返回的用户ID - if gotUid != tt.wantUid { - t.Errorf("GetUidFromCtx() 返回用户ID = %v, 期望值 %v", gotUid, tt.wantUid) - } - - // 检查错误类型 - if tt.wantError == nil && gotErr != nil { - t.Errorf("GetUidFromCtx() 返回意外错误 = %v", gotErr) - } - - if tt.wantError != nil && !errors.Is(gotErr, tt.wantError) { - t.Errorf("GetUidFromCtx() 错误类型 = %v, 期望错误类型 %v", gotErr, tt.wantError) - } - }) - } -} - -func TestIsNoUserIdError(t *testing.T) { - tests := []struct { - name string - err error - expected bool - }{ - { - name: "是未登录错误", - err: ErrNoUserIdInCtx, - expected: true, - }, - { - name: "包装的未登录错误", - err: errors.New("外层错误: " + ErrNoUserIdInCtx.Error()), - expected: false, // 直接字符串拼接不会保留错误链 - }, - { - name: "使用fmt.Errorf包装的未登录错误", - err: errors.New("外层错误"), - expected: false, - }, - { - name: "非未登录错误", - err: ErrInvalidUserId, - expected: false, - }, - { - name: "nil错误", - err: nil, - expected: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := IsNoUserIdError(tt.err); got != tt.expected { - t.Errorf("IsNoUserIdError() = %v, 期望值 %v", got, tt.expected) - } - }) - } -} - -func TestIsInvalidUserIdError(t *testing.T) { - tests := []struct { - name string - err error - expected bool - }{ - { - name: "是无效用户ID错误", - err: ErrInvalidUserId, - expected: true, - }, - { - name: "包装的无效用户ID错误", - err: errors.New("外层错误: " + ErrInvalidUserId.Error()), - expected: false, // 直接字符串拼接不会保留错误链 - }, - { - name: "使用fmt.Errorf包装的无效用户ID错误", - err: errors.New("外层错误"), - expected: false, - }, - { - name: "非无效用户ID错误", - err: ErrNoUserIdInCtx, - expected: false, - }, - { - name: "nil错误", - err: nil, - expected: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := IsInvalidUserIdError(tt.err); got != tt.expected { - t.Errorf("IsInvalidUserIdError() = %v, 期望值 %v", got, tt.expected) - } - }) - } -} diff --git a/common/jwt/jwtx.go b/common/jwt/jwtx.go index bae8de9..bc8be83 100644 --- a/common/jwt/jwtx.go +++ b/common/jwt/jwtx.go @@ -1,68 +1,94 @@ package jwtx import ( + "encoding/json" "errors" - "github.com/golang-jwt/jwt/v4" - "strconv" "time" + + "github.com/golang-jwt/jwt/v4" ) -// Token 生成逻辑的函数,接收 userId、过期时间和密钥,返回生成的 token -func GenerateJwtToken(userId int64, secret string, expireTime int64) (string, error) { - // 获取当前时间戳 - now := time.Now().Unix() - // 定义 JWT Claims - claims := jwt.MapClaims{ - "exp": now + expireTime, // token 过期时间 - "iat": now, // 签发时间 - "userId": userId, // 用户ID +const ExtraKey = "extra" + +type JwtClaims struct { + UserId int64 `json:"userId"` + AgentId int64 `json:"agentId"` + Platform string `json:"platform"` + // 用户身份类型:0-临时用户,1-正式用户 + UserType int64 `json:"userType"` + // 是否代理:0-否,1-是 + IsAgent int64 `json:"isAgent"` +} + +// MapToJwtClaims 将 map[string]interface{} 转换为 JwtClaims 结构体 +func MapToJwtClaims(claimsMap map[string]interface{}) (*JwtClaims, error) { + // 使用JSON序列化/反序列化的方式自动转换 + jsonData, err := json.Marshal(claimsMap) + if err != nil { + return nil, errors.New("序列化claims失败") } - // 创建新的 JWT token - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + var claims JwtClaims + if err := json.Unmarshal(jsonData, &claims); err != nil { + return nil, errors.New("反序列化claims失败") + } - // 使用密钥对 token 签名 - signedToken, err := token.SignedString([]byte(secret)) + return &claims, nil +} + +// GenerateJwtToken 生成JWT token +func GenerateJwtToken(claims JwtClaims, secret string, expire int64) (string, error) { + now := time.Now().Unix() + + // 将 claims 结构体转换为 map[string]interface{} + claimsBytes, err := json.Marshal(claims) if err != nil { return "", err } - return signedToken, nil + var claimsMap map[string]interface{} + if err := json.Unmarshal(claimsBytes, &claimsMap); err != nil { + return "", err + } + + jwtClaims := jwt.MapClaims{ + "exp": now + expire, + "iat": now, + "userId": claims.UserId, + ExtraKey: claimsMap, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaims) + return token.SignedString([]byte(secret)) } -func ParseJwtToken(tokenStr string, secret string) (int64, error) { + +func ParseJwtToken(tokenStr string, secret string) (*JwtClaims, error) { token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { return []byte(secret), nil }) if err != nil || !token.Valid { - return 0, errors.New("invalid JWT") + return nil, errors.New("invalid JWT") } claims, ok := token.Claims.(jwt.MapClaims) if !ok || !token.Valid { - return 0, errors.New("invalid JWT claims") + return nil, errors.New("invalid JWT claims") } - // 从 claims 中提取 userId - userIdRaw, ok := claims["userId"] - if !ok { - return 0, errors.New("userId not found in JWT") + extraInfo, exists := claims[ExtraKey] + if !exists { + return nil, errors.New("extra not found in JWT") } - // 处理不同类型的 userId,确保它被转换为 int64 - switch userId := userIdRaw.(type) { - case float64: - return int64(userId), nil - case int64: - return userId, nil - case string: - // 如果 userId 是字符串,可以尝试将其转换为 int64 - parsedId, err := strconv.ParseInt(userId, 10, 64) - if err != nil { - return 0, errors.New("invalid userId in JWT") - } - return parsedId, nil - default: - return 0, errors.New("unsupported userId type in JWT") + // 尝试直接断言为 JwtClaims 结构体 + if jwtClaims, ok := extraInfo.(JwtClaims); ok { + return &jwtClaims, nil } + + // 尝试从 map[string]interface{} 中解析 + if claimsMap, ok := extraInfo.(map[string]interface{}); ok { + return MapToJwtClaims(claimsMap) + } + + return nil, errors.New("unsupported extra type in JWT") } diff --git a/common/xerr/errCode.go b/common/xerr/errCode.go index 4d872e0..a461ca9 100644 --- a/common/xerr/errCode.go +++ b/common/xerr/errCode.go @@ -15,6 +15,7 @@ const DB_UPDATE_AFFECTED_ZERO_ERROR uint32 = 100006 const PARAM_VERIFICATION_ERROR uint32 = 100007 const CUSTOM_ERROR uint32 = 100008 const USER_NOT_FOUND uint32 = 100009 +const USER_NEED_BIND_MOBILE uint32 = 100010 const LOGIN_FAILED uint32 = 200001 const LOGIC_QUERY_WAIT uint32 = 200002 diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index bbcc047..1b911e3 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -33,9 +33,10 @@ $tables = @( # "query", # "query_cleanup_log" # "query_cleanup_detail" - "query_cleanup_config" + # "query_cleanup_config" # "user" # "user_auth" + "user_temp" # "example" # "admin_user" # "admin_user_role" diff --git a/pkg/lzkit/crypto/ecb_test.go b/pkg/lzkit/crypto/ecb_test.go index 9549cb0..bf49ed5 100644 --- a/pkg/lzkit/crypto/ecb_test.go +++ b/pkg/lzkit/crypto/ecb_test.go @@ -9,7 +9,7 @@ import ( func TestAesEcbMobileEncryption(t *testing.T) { // 测试手机号加密 - mobile := "13280082033 " + mobile := "17776203797 " key := []byte("ff83609b2b24fc73196aac3d3dfb874f") // 16字节AES-128密钥 keyStr := hex.EncodeToString(key) @@ -19,7 +19,7 @@ func TestAesEcbMobileEncryption(t *testing.T) { t.Fatalf("手机号加密失败: %v", err) } fmt.Printf("encrypted: %s\n", encrypted) - jmStr := "oEpLcrIpDPN63rOlESXTDg==" + jmStr := "m9EEeW9ZBBJmi1hx1k1uIQ==" // 测试解密 decrypted, err := DecryptMobile(jmStr, keyStr) if err != nil {