diff --git a/app/main/api/desc/admin/platform_user.api b/app/main/api/desc/admin/platform_user.api index 7ab5e63..82fc0f0 100644 --- a/app/main/api/desc/admin/platform_user.api +++ b/app/main/api/desc/admin/platform_user.api @@ -61,6 +61,7 @@ type ( Nickname string `json:"nickname"` // 昵称 Info string `json:"info"` // 备注信息 Inside int64 `json:"inside"` // 是否内部用户 1-是 0-否 + Disable int64 `json:"disable"` // 是否封禁 0-可用 1-禁用 CreateTime string `json:"create_time"` // 创建时间 UpdateTime string `json:"update_time"` // 更新时间 } @@ -77,6 +78,7 @@ type ( Nickname string `json:"nickname"` // 昵称 Info string `json:"info"` // 备注信息 Inside int64 `json:"inside"` // 是否内部用户 1-是 0-否 + Disable int64 `json:"disable"` // 是否封禁 0-可用 1-禁用 CreateTime string `json:"create_time"` // 创建时间 UpdateTime string `json:"update_time"` // 更新时间 } @@ -103,6 +105,7 @@ type ( Nickname *string `json:"nickname,optional"` // 昵称 Info *string `json:"info,optional"` // 备注信息 Inside *int64 `json:"inside,optional"` // 是否内部用户 1-是 0-否 + Disable *int64 `json:"disable,optional"` // 是否封禁 0-可用 1-禁用 } // 更新响应 diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index e3b4665..318ea8e 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -770,7 +770,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Middleware{serverCtx.UserDisableInterceptor, serverCtx.UserAuthInterceptor}, []rest.Route{ { Method: http.MethodGet, @@ -810,7 +810,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Middleware{serverCtx.UserDisableInterceptor, serverCtx.UserAuthInterceptor}, []rest.Route{ { Method: http.MethodPost, @@ -830,7 +830,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Middleware{serverCtx.UserDisableInterceptor, serverCtx.UserAuthInterceptor}, []rest.Route{ { Method: http.MethodGet, @@ -880,7 +880,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.AuthInterceptor}, + []rest.Middleware{serverCtx.AuthInterceptor, serverCtx.UserDisableInterceptor}, []rest.Route{ { Method: http.MethodPost, @@ -987,7 +987,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Middleware{serverCtx.UserDisableInterceptor, serverCtx.UserAuthInterceptor}, []rest.Route{ { Method: http.MethodPost, @@ -1039,7 +1039,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.AuthInterceptor}, + []rest.Middleware{serverCtx.AuthInterceptor, serverCtx.UserDisableInterceptor}, []rest.Route{ { // query service agent @@ -1059,7 +1059,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Middleware{serverCtx.UserDisableInterceptor, serverCtx.UserAuthInterceptor}, []rest.Route{ { // query service @@ -1075,7 +1075,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.UserAuthInterceptor}, + []rest.Middleware{serverCtx.UserDisableInterceptor, serverCtx.UserAuthInterceptor}, []rest.Route{ { // 生成分享链接 @@ -1179,7 +1179,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( rest.WithMiddlewares( - []rest.Middleware{serverCtx.AuthInterceptor}, + []rest.Middleware{serverCtx.AuthInterceptor, serverCtx.UserDisableInterceptor}, []rest.Route{ { // 绑定手机号 diff --git a/app/main/api/internal/logic/admin_platform_user/admingetplatformuserdetaillogic.go b/app/main/api/internal/logic/admin_platform_user/admingetplatformuserdetaillogic.go index 92d5088..44355d1 100644 --- a/app/main/api/internal/logic/admin_platform_user/admingetplatformuserdetaillogic.go +++ b/app/main/api/internal/logic/admin_platform_user/admingetplatformuserdetaillogic.go @@ -43,6 +43,7 @@ func (l *AdminGetPlatformUserDetailLogic) AdminGetPlatformUserDetail(req *types. Nickname: "", Info: user.Info, Inside: user.Inside, + Disable: user.Disable, CreateTime: user.CreateTime.Format("2006-01-02 15:04:05"), UpdateTime: user.UpdateTime.Format("2006-01-02 15:04:05"), } diff --git a/app/main/api/internal/logic/admin_platform_user/admingetplatformuserlistlogic.go b/app/main/api/internal/logic/admin_platform_user/admingetplatformuserlistlogic.go index 74fd1d1..821dc4b 100644 --- a/app/main/api/internal/logic/admin_platform_user/admingetplatformuserlistlogic.go +++ b/app/main/api/internal/logic/admin_platform_user/admingetplatformuserlistlogic.go @@ -31,7 +31,12 @@ func NewAdminGetPlatformUserListLogic(ctx context.Context, svcCtx *svc.ServiceCo func (l *AdminGetPlatformUserListLogic) AdminGetPlatformUserList(req *types.AdminGetPlatformUserListReq) (resp *types.AdminGetPlatformUserListResp, err error) { builder := l.svcCtx.UserModel.SelectBuilder() if req.Mobile != "" { - builder = builder.Where("mobile = ?", req.Mobile) + // 数据库手机号为密文,需加密明文手机号后再查询 + encryptedMobile, err := crypto.EncryptMobile(req.Mobile, l.svcCtx.Config.Encrypt.SecretKey) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机号加密失败: %v", err) + } + builder = builder.Where("mobile = ?", encryptedMobile) } if req.Nickname != "" { builder = builder.Where("nickname = ?", req.Nickname) @@ -72,6 +77,7 @@ func (l *AdminGetPlatformUserListLogic) AdminGetPlatformUserList(req *types.Admi Nickname: "", Info: user.Info, Inside: user.Inside, + Disable: user.Disable, CreateTime: user.CreateTime.Format("2006-01-02 15:04:05"), UpdateTime: user.UpdateTime.Format("2006-01-02 15:04:05"), } diff --git a/app/main/api/internal/logic/admin_platform_user/adminupdateplatformuserlogic.go b/app/main/api/internal/logic/admin_platform_user/adminupdateplatformuserlogic.go index 9bb9a64..d4c1547 100644 --- a/app/main/api/internal/logic/admin_platform_user/adminupdateplatformuserlogic.go +++ b/app/main/api/internal/logic/admin_platform_user/adminupdateplatformuserlogic.go @@ -52,6 +52,12 @@ func (l *AdminUpdatePlatformUserLogic) AdminUpdatePlatformUser(req *types.AdminU } user.Inside = *req.Inside } + if req.Disable != nil { + if *req.Disable != 1 && *req.Disable != 0 { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "封禁状态错误: %d", *req.Disable) + } + user.Disable = *req.Disable + } if req.Password != nil { user.Password = sql.NullString{String: *req.Password, Valid: *req.Password != ""} } diff --git a/app/main/api/internal/middleware/userdisableinterceptor_middleware.go b/app/main/api/internal/middleware/userdisableinterceptor_middleware.go new file mode 100644 index 0000000..3922aca --- /dev/null +++ b/app/main/api/internal/middleware/userdisableinterceptor_middleware.go @@ -0,0 +1,60 @@ +package middleware + +import ( + "net/http" + + "tyc-server/app/main/model" + "tyc-server/common/ctxdata" + "tyc-server/common/result" + "tyc-server/common/xerr" + + "github.com/zeromicro/go-zero/rest/httpx" +) + +// UserDisableInterceptorMiddleware 检查用户是否被封禁,封禁用户直接拦截并返回错误 +type UserDisableInterceptorMiddleware struct { + UserModel model.UserModel +} + +// NewUserDisableInterceptorMiddleware 创建用户封禁检查中间件 +func NewUserDisableInterceptorMiddleware(userModel model.UserModel) *UserDisableInterceptorMiddleware { + return &UserDisableInterceptorMiddleware{ + UserModel: userModel, + } +} + +// Handle 处理请求:当用户已登录且被封禁时,直接返回错误 +func (m *UserDisableInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + claims, err := ctxdata.GetClaimsFromCtx(r.Context()) + if err != nil { + // 无登录信息,放行(由后续认证中间件处理) + next(w, r) + return + } + + // 管理员不检查 user 表的 disable 字段 + if claims.UserType == model.UserTypeAdmin { + next(w, r) + return + } + + // 查询用户是否被封禁 + user, err := m.UserModel.FindOne(r.Context(), claims.UserId) + if err != nil { + // 用户不存在(如管理员账号)或查询失败,放行 + next(w, r) + return + } + + // 1 表示已禁用 + if user.Disable == 1 { + errcode := xerr.USER_DISABLED + errmsg := xerr.MapErrMsg(errcode) + httpx.WriteJson(w, http.StatusOK, result.Error(errcode, errmsg)) + return + } + + next(w, r) + } +} diff --git a/app/main/api/internal/svc/servicecontext.go b/app/main/api/internal/svc/servicecontext.go index 284fef0..c074a44 100644 --- a/app/main/api/internal/svc/servicecontext.go +++ b/app/main/api/internal/svc/servicecontext.go @@ -21,9 +21,10 @@ type ServiceContext struct { Redis *redis.Redis // 中间件 - AuthInterceptor rest.Middleware - UserAuthInterceptor rest.Middleware - AdminAuthInterceptor rest.Middleware + AuthInterceptor rest.Middleware + UserAuthInterceptor rest.Middleware + UserDisableInterceptor rest.Middleware + AdminAuthInterceptor rest.Middleware // 用户相关模型 UserModel model.UserModel @@ -224,8 +225,9 @@ func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ Config: c, Redis: redisClient, - AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle, - UserAuthInterceptor: middleware.NewUserAuthInterceptorMiddleware().Handle, + AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle, + UserAuthInterceptor: middleware.NewUserAuthInterceptorMiddleware().Handle, + UserDisableInterceptor: middleware.NewUserDisableInterceptorMiddleware(userModel).Handle, AdminAuthInterceptor: middleware.NewAdminAuthInterceptorMiddleware(c, adminUserModel, adminUserRoleModel, adminRoleModel, adminApiModel, adminRoleApiModel).Handle, diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index 1ca7377..8604e0f 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -568,6 +568,7 @@ type AdminGetPlatformUserDetailResp struct { Nickname string `json:"nickname"` // 昵称 Info string `json:"info"` // 备注信息 Inside int64 `json:"inside"` // 是否内部用户 1-是 0-否 + Disable int64 `json:"disable"` // 是否封禁 0-可用 1-禁用 CreateTime string `json:"create_time"` // 创建时间 UpdateTime string `json:"update_time"` // 更新时间 } @@ -949,12 +950,13 @@ type AdminUpdateOrderResp struct { } type AdminUpdatePlatformUserReq struct { - Id int64 `path:"id"` // 用户ID - Mobile *string `json:"mobile,optional"` // 手机号 - Password *string `json:"password,optional"` // 密码 - Nickname *string `json:"nickname,optional"` // 昵称 - Info *string `json:"info,optional"` // 备注信息 - Inside *int64 `json:"inside,optional"` // 是否内部用户 1-是 0-否 + Id int64 `path:"id"` // 用户ID + Mobile *string `json:"mobile,optional"` // 手机号 + Password *string `json:"password,optional"` // 密码 + Nickname *string `json:"nickname,optional"` // 昵称 + Info *string `json:"info,optional"` // 备注信息 + Inside *int64 `json:"inside,optional"` // 是否内部用户 1-是 0-否 + Disable *int64 `json:"disable,optional"` // 是否封禁 0-可用 1-禁用 } type AdminUpdatePlatformUserResp struct { @@ -1861,6 +1863,7 @@ type PlatformUserListItem struct { Nickname string `json:"nickname"` // 昵称 Info string `json:"info"` // 备注信息 Inside int64 `json:"inside"` // 是否内部用户 1-是 0-否 + Disable int64 `json:"disable"` // 是否封禁 0-可用 1-禁用 CreateTime string `json:"create_time"` // 创建时间 UpdateTime string `json:"update_time"` // 更新时间 } diff --git a/app/main/model/userModel_gen.go b/app/main/model/userModel_gen.go index 7ffc6eb..b600c58 100644 --- a/app/main/model/userModel_gen.go +++ b/app/main/model/userModel_gen.go @@ -68,6 +68,7 @@ type ( Nickname sql.NullString `db:"nickname"` Info string `db:"info"` Inside int64 `db:"inside"` + Disable int64 `db:"disable"` // 0可用 1禁用 } ) @@ -83,11 +84,11 @@ func (m *defaultUserModel) Insert(ctx context.Context, session sqlx.Session, dat tycUserIdKey := fmt.Sprintf("%s%v", cacheTycUserIdPrefix, data.Id) tycUserMobileKey := fmt.Sprintf("%s%v", cacheTycUserMobilePrefix, data.Mobile) 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, userRowsExpectAutoSet) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet) if session != nil { - return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.Mobile, data.Password, data.Nickname, data.Info, data.Inside) + return session.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.Mobile, data.Password, data.Nickname, data.Info, data.Inside, data.Disable) } - return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.Mobile, data.Password, data.Nickname, data.Info, data.Inside) + return conn.ExecCtx(ctx, query, data.DeleteTime, data.DelState, data.Version, data.Mobile, data.Password, data.Nickname, data.Info, data.Inside, data.Disable) }, tycUserIdKey, tycUserMobileKey) } @@ -138,9 +139,9 @@ func (m *defaultUserModel) Update(ctx context.Context, session sqlx.Session, new 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, userRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Id) + return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Disable, newData.Id) } - return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Id) + return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Disable, newData.Id) }, tycUserIdKey, tycUserMobileKey) } @@ -161,9 +162,9 @@ func (m *defaultUserModel) UpdateWithVersion(ctx context.Context, session sqlx.S 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, userRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Id, oldVersion) + return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Disable, newData.Id, oldVersion) } - return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Id, oldVersion) + return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.Mobile, newData.Password, newData.Nickname, newData.Info, newData.Inside, newData.Disable, newData.Id, oldVersion) }, tycUserIdKey, tycUserMobileKey) if err != nil { return err diff --git a/common/xerr/errCode.go b/common/xerr/errCode.go index a461ca9..035cd1d 100644 --- a/common/xerr/errCode.go +++ b/common/xerr/errCode.go @@ -16,6 +16,7 @@ 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 USER_DISABLED uint32 = 100011 // 用户已被封禁 const LOGIN_FAILED uint32 = 200001 const LOGIC_QUERY_WAIT uint32 = 200002 diff --git a/common/xerr/errMsg.go b/common/xerr/errMsg.go index dc911f1..806af70 100644 --- a/common/xerr/errMsg.go +++ b/common/xerr/errMsg.go @@ -11,6 +11,7 @@ func init() { message[TOKEN_GENERATE_ERROR] = "生成token失败" message[DB_ERROR] = "系统维护升级中,请稍后再试" message[DB_UPDATE_AFFECTED_ZERO_ERROR] = "更新数据影响行数为0" + message[USER_DISABLED] = "您的账号已被封禁,如有疑问请联系客服" } func MapErrMsg(errcode uint32) string { diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index 655ad9c..c2c104c 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -37,7 +37,7 @@ $tables = @( # "query_cleanup_log" # "query_cleanup_detail" # "query_cleanup_config" - # "user" + "user" # "user_auth" # "user_temp" # "example" @@ -54,7 +54,7 @@ $tables = @( # "admin_promotion_link_stats_total" # "admin_promotion_link_stats_history" # "admin_promotion_order" - "query_user_record" + # "query_user_record" ) diff --git a/deploy/sql/user_add_disable.sql b/deploy/sql/user_add_disable.sql new file mode 100644 index 0000000..97965a5 --- /dev/null +++ b/deploy/sql/user_add_disable.sql @@ -0,0 +1,2 @@ +-- 为用户表添加 disable 字段:0 可用,1 禁用,默认 0 +ALTER TABLE `user` ADD COLUMN `disable` tinyint NOT NULL DEFAULT 0 COMMENT '0可用 1禁用' AFTER `inside`;