Files
ycc-proxy-server/app/main/api/internal/logic/user/wxh5authlogic.go
2025-12-10 14:10:15 +08:00

141 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"ycc-server/app/main/model"
"ycc-server/common/xerr"
"github.com/google/uuid"
"github.com/pkg/errors"
"ycc-server/app/main/api/internal/svc"
"ycc-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type WxH5AuthLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWxH5AuthLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WxH5AuthLogic {
return &WxH5AuthLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthResp, err error) {
l.Infof("🔄 WxH5Auth 开始处理微信H5授权请求")
// Step 1: 使用code获取access_token
l.Infof("📡 Step 1: 使用code获取access_token, code=%s", req.Code)
accessTokenResp, err := l.GetAccessToken(req.Code)
if err != nil {
l.Errorf("❌ 获取access_token失败: %v", err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err)
}
l.Infof("✅ 成功获取access_token, openid=%s", accessTokenResp.Openid)
// Step 2: 查找用户授权信息
l.Infof("📡 Step 2: 查找用户授权信息, auth_type=%s, openid=%s", model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
l.Errorf("❌ 查询用户授权失败: %v", findErr)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户授权失败: %v", findErr)
}
// Step 3: 处理用户信息
var userID string
if userAuth != nil {
// 已存在用户,直接登录
userID = userAuth.UserId
l.Infof("✅ 用户已存在, userID=%s, openid=%s", userID, accessTokenResp.Openid)
} else {
// 新用户创建为临时用户没有mobile
l.Infof("📝 Step 3a: 创建新的临时用户, openid=%s", accessTokenResp.Openid)
user := &model.User{Id: uuid.NewString()}
_, err := l.svcCtx.UserModel.Insert(l.ctx, nil, user)
if err != nil {
l.Errorf("❌ 创建User失败: userID=%s, error=%v", user.Id, err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户失败: %v", err)
}
l.Infof("✅ User创建成功: userID=%s, mobile=null (临时用户)", user.Id)
l.Infof("📝 Step 3b: 创建UserAuth记录, userID=%s, openid=%s", user.Id, accessTokenResp.Openid)
ua := &model.UserAuth{Id: uuid.NewString(), UserId: user.Id, AuthType: model.UserAuthTypeWxh5OpenID, AuthKey: accessTokenResp.Openid}
_, err = l.svcCtx.UserAuthModel.Insert(l.ctx, nil, ua)
if err != nil {
l.Errorf("❌ 创建UserAuth失败: userID=%s, openid=%s, error=%v", user.Id, accessTokenResp.Openid, err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户授权失败: %v", err)
}
l.Infof("✅ UserAuth创建成功: userAuthID=%s, userID=%s, authType=%s", ua.Id, user.Id, model.UserAuthTypeWxh5OpenID)
userID = user.Id
l.Infof("✅ 新建临时用户完成: userID=%s, openid=%s", userID, accessTokenResp.Openid)
}
// Step 4: 生成JWT Token动态计算userType
l.Infof("📡 Step 4: 生成JWT Token, userID=%s", userID)
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
l.Errorf("❌ 生成token失败: userID=%s, error=%v", userID, err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err)
}
l.Infof("✅ Token生成成功: userID=%s, tokenLen=%d", userID, len(token))
// Step 5: 返回登录结果
l.Infof("📡 Step 5: 返回登录结果")
now := time.Now().Unix()
resp = &types.WXH5AuthResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}
l.Infof("🎯 WxH5Auth完成: userID=%s, accessExpire=%d, refreshAfter=%d", userID, resp.AccessExpire, resp.RefreshAfter)
return resp, nil
}
type AccessTokenResp struct {
AccessToken string `json:"access_token"`
Openid string `json:"openid"`
}
// GetAccessToken 通过code获取access_token
func (l *WxH5AuthLogic) GetAccessToken(code string) (*AccessTokenResp, error) {
appID := l.svcCtx.Config.WechatH5.AppID
appSecret := l.svcCtx.Config.WechatH5.AppSecret
url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appID, appSecret, code)
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var accessTokenResp AccessTokenResp
if err = json.Unmarshal(body, &accessTokenResp); err != nil {
return nil, err
}
if accessTokenResp.AccessToken == "" || accessTokenResp.Openid == "" {
return nil, errors.New("accessTokenResp.AccessToken为空")
}
return &accessTokenResp, nil
}