This commit is contained in:
Mrx
2026-02-04 13:33:21 +08:00
parent e7c2ddbd93
commit e1fbf72437
23 changed files with 190 additions and 65 deletions

View File

@@ -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-封禁
}
// 更新响应

View File

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

View File

@@ -30,8 +30,14 @@ 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()
secretKey := l.svcCtx.Config.Encrypt.SecretKey
if req.Mobile != "" {
builder = builder.Where("mobile = ?", req.Mobile)
// 数据库存密文,筛选时用明文加密后再匹配
encryptedMobile, encErr := crypto.EncryptMobile(req.Mobile, secretKey)
if encErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机号加密失败: %v", encErr)
}
builder = builder.Where("mobile = ?", encryptedMobile)
}
if req.Nickname != "" {
builder = builder.Where("nickname = ?", req.Nickname)
@@ -55,8 +61,6 @@ func (l *AdminGetPlatformUserListLogic) AdminGetPlatformUserList(req *types.Admi
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户分页失败: %v", err)
}
var items []types.PlatformUserListItem
secretKey := l.svcCtx.Config.Encrypt.SecretKey
for _, user := range users {
mobile := user.Mobile
if mobile.Valid {
@@ -72,6 +76,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"),
}

View File

@@ -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 != ""}
}

View File

@@ -40,8 +40,8 @@ func NewQueryServiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Quer
func (l *QueryServiceLogic) QueryService(req *types.QueryServiceReq) (resp *types.QueryServiceResp, err error) {
if req.AgentIdentifier != "" {
return nil, errors.Wrapf(xerr.NewErrMsg("系统正在升级,查询服务暂不可用,恢复时间待定"), "查询服务暂停, AgentIdentifier: %s", req.AgentIdentifier)
// l.ctx = context.WithValue(l.ctx, "agentIdentifier", req.AgentIdentifier)
// return nil, errors.Wrapf(xerr.NewErrMsg("系统正在升级,查询服务暂不可用,恢复时间待定"), "查询服务暂停, AgentIdentifier: %s", req.AgentIdentifier)
l.ctx = context.WithValue(l.ctx, "agentIdentifier", req.AgentIdentifier)
} else if req.App {
l.ctx = context.WithValue(l.ctx, "app", req.App)
}

View File

@@ -97,6 +97,10 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
if err != nil {
causeErr := errors.Cause(err)
if _, ok := causeErr.(*xerr.CodeError); ok {
return nil, err
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 生成token失败: %+v", err)
}
now := time.Now().Unix()

View File

@@ -2,9 +2,9 @@ package user
import (
"context"
"time"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"time"
"github.com/pkg/errors"
@@ -35,6 +35,10 @@ func (l *GetTokenLogic) GetToken() (resp *types.MobileCodeLoginResp, err error)
}
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, claims.UserId, claims.UserType)
if err != nil {
causeErr := errors.Cause(err)
if _, ok := causeErr.(*xerr.CodeError); ok {
return nil, err
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err)
}
// 获取当前时间戳

View File

@@ -68,7 +68,12 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r
}
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID)
// 封禁等业务错误原样返回,便于前端展示「用户已被封禁」
causeErr := errors.Cause(err)
if _, ok := causeErr.(*xerr.CodeError); ok {
return nil, err
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d, %v", userID, err)
}
// 获取当前时间戳

View File

@@ -2,13 +2,13 @@ package user
import (
"context"
"tydata-server/app/main/model"
"tydata-server/common/xerr"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"tydata-server/app/main/model"
"tydata-server/common/xerr"
"github.com/pkg/errors"
@@ -82,6 +82,10 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe
// Step 4: 生成JWT Token
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, userType)
if err != nil {
causeErr := errors.Cause(err)
if _, ok := causeErr.(*xerr.CodeError); ok {
return nil, err
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err)
}

View File

@@ -81,6 +81,10 @@ func (l *WxMiniAuthLogic) WxMiniAuth(req *types.WXMiniAuthReq) (resp *types.WXMi
// 4. 生成JWT Token
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, userType)
if err != nil {
causeErr := errors.Cause(err)
if _, ok := causeErr.(*xerr.CodeError); ok {
return nil, err
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT Token失败: %v", err)
}

View File

@@ -1,10 +1,10 @@
package middleware
import (
"net/http"
"tydata-server/app/main/model"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"net/http"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/rest/httpx"

View File

@@ -0,0 +1,69 @@
package middleware
import (
"net/http"
"strings"
"tydata-server/app/main/api/internal/config"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/result"
"tydata-server/common/xerr"
"github.com/zeromicro/go-zero/rest/httpx"
)
// UserDisableCheckMiddleware 全局中间件:若当前用户已被封禁(disable=1),则拒绝请求并返回封禁原因
type UserDisableCheckMiddleware struct {
Config config.Config
UserModel model.UserModel
}
// NewUserDisableCheckMiddleware 创建封禁检查中间件
func NewUserDisableCheckMiddleware(c config.Config, userModel model.UserModel) *UserDisableCheckMiddleware {
return &UserDisableCheckMiddleware{
Config: c,
UserModel: userModel,
}
}
// Handle 仅对携带用户 JWT 的请求做封禁校验;无 token 或 admin token 直接放行
func (m *UserDisableCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
next(w, r)
return
}
token := strings.TrimPrefix(authHeader, "Bearer ")
if token == authHeader {
next(w, r)
return
}
// 仅使用用户端 JWT 密钥解析;管理员 token 会解析失败,直接放行由后续中间件处理
claims, err := jwtx.ParseJwtToken(token, m.Config.JwtAuth.AccessSecret)
if err != nil {
next(w, r)
return
}
// 查封禁状态不走缓存,封禁后立即生效,已登录用户下次请求即被拒绝
disable, err := m.UserModel.FindDisableByUserId(r.Context(), claims.UserId)
if err != nil {
next(w, r)
return
}
// disable: 0 可用1 封禁
if disable == 1 {
errcode := xerr.USER_DISABLED
errmsg := xerr.MapErrMsg(errcode)
httpx.WriteJson(w, http.StatusForbidden, result.Error(errcode, errmsg))
return
}
next(w, r)
}
}

View File

@@ -2,12 +2,12 @@ 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"
"database/sql"
"github.com/google/uuid"
"github.com/pkg/errors"
@@ -78,6 +78,17 @@ func (s *UserService) RegisterUUIDUser(ctx context.Context) (int64, error) {
// generalUserToken 生成用户token
func (s *UserService) GeneralUserToken(ctx context.Context, userID int64, userType int64) (string, error) {
// 正式用户签发 token 前校验是否被封禁,封禁用户不允许登录
if userType == model.UserTypeNormal {
user, err := s.userModel.FindOne(ctx, userID)
if err != nil {
return "", err
}
if user != nil && user.Disable == 1 {
return "", errors.Wrapf(xerr.NewErrCode(xerr.USER_DISABLED), "用户已被封禁")
}
}
platform, err := ctxdata.GetPlatformFromCtx(ctx)
if err != nil {
return "", err

View File

@@ -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,6 +950,7 @@ type AdminUpdatePlatformUserReq struct {
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 {
@@ -1854,6 +1856,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"` // 更新时间
}

View File

@@ -68,6 +68,7 @@ func main() {
server := rest.MustNewServer(c.RestConf)
server.Use(middleware.GlobalSourceInterceptor)
server.Use(middleware.NewUserDisableCheckMiddleware(svcContext.Config, svcContext.UserModel).Handle)
defer server.Stop()
handler.RegisterHandlers(server, svcContext)