tyc-server/app/main/api/internal/logic/user/wxminiauthlogic.go

152 lines
4.6 KiB
Go
Raw Normal View History

2024-11-03 15:28:10 +08:00
package user
import (
"context"
2025-01-18 22:34:27 +08:00
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"
2025-04-27 12:17:18 +08:00
"tyc-server/app/main/api/internal/svc"
"tyc-server/app/main/api/internal/types"
"tyc-server/app/main/model"
2025-04-09 15:58:06 +08:00
jwtx "tyc-server/common/jwt"
"tyc-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
2024-11-03 15:28:10 +08:00
"github.com/zeromicro/go-zero/core/logx"
)
type WxMiniAuthLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWxMiniAuthLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WxMiniAuthLogic {
return &WxMiniAuthLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WxMiniAuthLogic) WxMiniAuth(req *types.WXMiniAuthReq) (resp *types.WXMiniAuthResp, err error) {
2025-01-18 22:34:27 +08:00
// 1. 使用微信提供的 code 换取 session_key 和 openid
weChatResponse, err := l.exchangeCodeForSession(req.Code)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrMsg("微信登录失败"), "微信登录, code 换取 session 失败: %s, err: %+v", req.Code, err)
}
// 2. 根据 openid 查找用户
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxMini, weChatResponse.OpenId)
if findErr != nil && findErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "微信登录, 读取用户认证信息失败, openid: %s, err: %+v", weChatResponse.OpenId, findErr)
}
var user *model.User
if findErr == model.ErrNotFound {
// 用户不存在,创建新用户
user = &model.User{}
2025-01-18 23:21:48 +08:00
user.Mobile = weChatResponse.OpenId
2025-01-18 22:34:27 +08:00
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
// 插入新用户
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "微信登录, 数据库插入新用户失败, openid: %s, err: %+v", weChatResponse.OpenId, userInsertErr)
}
// 获取新用户的 ID
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "微信登录, 获取新用户ID失败, err:%+v, user:%+v", lastInsertIdErr, user)
}
user.Id = lastId
2024-11-03 15:28:10 +08:00
2025-01-18 22:34:27 +08:00
// 创建用户认证信息
newUserAuth := &model.UserAuth{
UserId: lastId,
AuthKey: weChatResponse.OpenId,
AuthType: model.UserAuthTypeWxMini,
}
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, newUserAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "微信登录, 数据库插入用户认证信息失败, err:%+v", userAuthInsertErr)
}
return nil
}); transErr != nil {
return nil, transErr
}
} else {
// 获取用户信息
user, err = l.svcCtx.UserModel.FindOne(l.ctx, userAuth.UserId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "微信登录, 读取用户信息失败, userId: %d, err: %+v", userAuth.UserId, err)
}
}
// 3. 生成 JWT 令牌
token, generateErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generateErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "微信登录, 生成token失败 : %d", user.Id)
}
// 4. 获取当前时间戳
now := time.Now().Unix()
return &types.WXMiniAuthResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}
type WxLoginResp struct {
OpenId string `json:"openid"`
SessionKey string `json:"session_key"`
Unionid string `json:"unionid"`
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
func (l *WxMiniAuthLogic) exchangeCodeForSession(code string) (response WxLoginResp, err error) {
// 向微信发出登录请求
baseURL := "https://api.weixin.qq.com/sns/jscode2session"
// 创建查询参数
params := url.Values{}
params.Add("appid", l.svcCtx.Config.Wxpay.AppID)
params.Add("secret", l.svcCtx.Config.Wxpay.AppSecret)
params.Add("js_code", code)
params.Add("grant_type", "authorization_code")
// 构建完整的请求 URL
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
// 发送 GET 请求
resp, err := http.Get(requestURL)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return
}
// 将响应体解析为结构体
err = json.Unmarshal(body, &response)
if err != nil {
return
}
if response.ErrCode != 0 {
err = errors.New(response.ErrMsg)
return
}
2024-11-03 15:28:10 +08:00
return
}