From 867a1022dd714a068ece0b7d255ac663898059d9 Mon Sep 17 00:00:00 2001 From: Mrx <18278715334@163.com> Date: Mon, 11 May 2026 20:21:56 +0800 Subject: [PATCH] f --- .../internal/handler/user/wxh5authhandler.go | 12 ++++- .../api/internal/logic/user/wxh5authlogic.go | 54 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/app/main/api/internal/handler/user/wxh5authhandler.go b/app/main/api/internal/handler/user/wxh5authhandler.go index 3605489..2804f0a 100644 --- a/app/main/api/internal/handler/user/wxh5authhandler.go +++ b/app/main/api/internal/handler/user/wxh5authhandler.go @@ -1,11 +1,14 @@ package user import ( + "context" "net/http" + "strings" "tyc-server/app/main/api/internal/logic/user" "tyc-server/app/main/api/internal/svc" "tyc-server/app/main/api/internal/types" + jwtx "tyc-server/common/jwt" "tyc-server/common/result" "tyc-server/pkg/lzkit/validator" @@ -23,7 +26,14 @@ func WxH5AuthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { result.ParamValidateErrorResult(r, w, err) return } - l := user.NewWxH5AuthLogic(r.Context(), svcCtx) + ctx := r.Context() + // 本路由未挂 AuthInterceptor;若前端已带登录态(如手机号登录后再走静默授权),需解析 JWT 以便把 openid 写入当前正式用户 user_auth + if authHeader := strings.TrimSpace(r.Header.Get("Authorization")); authHeader != "" { + if claims, err := jwtx.ParseJwtToken(authHeader, svcCtx.Config.JwtAuth.AccessSecret); err == nil { + ctx = context.WithValue(ctx, jwtx.ExtraKey, claims) + } + } + l := user.NewWxH5AuthLogic(ctx, svcCtx) resp, err := l.WxH5Auth(&req) result.HttpResult(r, w, resp, err) } diff --git a/app/main/api/internal/logic/user/wxh5authlogic.go b/app/main/api/internal/logic/user/wxh5authlogic.go index 233a809..15952eb 100644 --- a/app/main/api/internal/logic/user/wxh5authlogic.go +++ b/app/main/api/internal/logic/user/wxh5authlogic.go @@ -6,8 +6,10 @@ import ( "fmt" "io" "net/http" + "strings" "time" "tyc-server/app/main/model" + "tyc-server/common/ctxdata" "tyc-server/common/xerr" "github.com/pkg/errors" @@ -39,6 +41,11 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err) } + // 已登录正式用户 + 静默授权 code:把当前公众号 openid 写入 user_auth(wxh5_openid),供微信内 JSAPI 支付使用 + if claims, claimsErr := ctxdata.GetClaimsFromCtx(l.ctx); claimsErr == nil && claims != nil && claims.UserType == model.UserTypeNormal { + return l.bindWxh5OpenidToNormalUser(claims.UserId, accessTokenResp.Openid) + } + // Step 2: 查找用户授权信息 userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid) if findErr != nil && !errors.Is(findErr, model.ErrNotFound) { @@ -94,6 +101,53 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe }, nil } +// bindWxh5OpenidToNormalUser 将 snsapi_base 换得的 openid 绑定到当前正式用户(插入或更新 user_auth)。 +// 临时用户不能走此分支:需在绑定手机号时由 TempUserBindUser 写入 user_auth,避免与临时转正逻辑冲突。 +func (l *WxH5AuthLogic) bindWxh5OpenidToNormalUser(normalUserID int64, openid string) (*types.WXH5AuthResp, error) { + openid = strings.TrimSpace(openid) + if openid == "" { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "微信 openid 为空") + } + existingByOpenid, err := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, openid) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询 wxh5_openid 失败: %v", err) + } + if existingByOpenid != nil && existingByOpenid.UserId != normalUserID { + return nil, errors.Wrapf(xerr.NewErrMsg("该微信已绑定其他账号"), "wxh5_openid 已被占用 user_id=%d", existingByOpenid.UserId) + } + rowByUser, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, normalUserID, model.UserAuthTypeWxh5OpenID) + if errors.Is(err, model.ErrNotFound) { + _, insErr := l.svcCtx.UserAuthModel.Insert(l.ctx, nil, &model.UserAuth{ + UserId: normalUserID, + AuthType: model.UserAuthTypeWxh5OpenID, + AuthKey: openid, + }) + if insErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "写入 wxh5_openid 失败: %v", insErr) + } + logx.WithContext(l.ctx).Infof("[WxH5Auth] 已写入 user_auth wxh5_openid user_id=%d", normalUserID) + } else if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户 wxh5_openid 失败: %v", err) + } else if rowByUser.AuthKey != openid { + rowByUser.AuthKey = openid + if _, updErr := l.svcCtx.UserAuthModel.Update(l.ctx, nil, rowByUser); updErr != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新 wxh5_openid 失败: %v", updErr) + } + logx.WithContext(l.ctx).Infof("[WxH5Auth] 已更新 user_auth wxh5_openid user_id=%d", normalUserID) + } + + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, normalUserID, model.UserTypeNormal) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err) + } + now := time.Now().Unix() + return &types.WXH5AuthResp{ + AccessToken: token, + AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, + RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter, + }, nil +} + type AccessTokenResp struct { AccessToken string `json:"access_token"` Openid string `json:"openid"`