This commit is contained in:
Mrx
2026-05-11 20:21:56 +08:00
parent 0d476fa477
commit 867a1022dd
2 changed files with 65 additions and 1 deletions

View File

@@ -1,11 +1,14 @@
package user package user
import ( import (
"context"
"net/http" "net/http"
"strings"
"tyc-server/app/main/api/internal/logic/user" "tyc-server/app/main/api/internal/logic/user"
"tyc-server/app/main/api/internal/svc" "tyc-server/app/main/api/internal/svc"
"tyc-server/app/main/api/internal/types" "tyc-server/app/main/api/internal/types"
jwtx "tyc-server/common/jwt"
"tyc-server/common/result" "tyc-server/common/result"
"tyc-server/pkg/lzkit/validator" "tyc-server/pkg/lzkit/validator"
@@ -23,7 +26,14 @@ func WxH5AuthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
result.ParamValidateErrorResult(r, w, err) result.ParamValidateErrorResult(r, w, err)
return 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) resp, err := l.WxH5Auth(&req)
result.HttpResult(r, w, resp, err) result.HttpResult(r, w, resp, err)
} }

View File

@@ -6,8 +6,10 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"strings"
"time" "time"
"tyc-server/app/main/model" "tyc-server/app/main/model"
"tyc-server/common/ctxdata"
"tyc-server/common/xerr" "tyc-server/common/xerr"
"github.com/pkg/errors" "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) 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: 查找用户授权信息 // Step 2: 查找用户授权信息
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid) userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) { if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
@@ -94,6 +101,53 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe
}, nil }, 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 { type AccessTokenResp struct {
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
Openid string `json:"openid"` Openid string `json:"openid"`