package auth import ( "allapp/api/types" "allapp/config" "allapp/db" "allapp/db/repo" "allapp/utils" "allapp/utils/errorx" "allapp/utils/httpx" "allapp/utils/jwtx" "allapp/utils/requestx" "allapp/utils/responsex" "allapp/utils/uniqueid" "errors" "fmt" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/client" ) // LoginQq qq登录 func LoginQq(c fiber.Ctx) error { dto := new(types.LoginQqDTO) vo := new(types.LoginVO) if err := requestx.BindAndValidate(c, dto); err != nil { return err } return handleThirdLogin( c, dto.Openid, dto.Nickname, dto.Avatar, 1, // QQ vo, ) } func LoginWechat(c fiber.Ctx) error { dto := new(types.LoginWeixinDTO) vo := new(types.LoginVO) if err := requestx.BindAndValidate(c, dto); err != nil { return err } openid, accessToken, err := getWechatAccess(dto.Code) if err != nil { return responsex.Error(c, "微信登录失败,请重试") } // 查是否已存在用户 _, err = db.Queries.FindUserByOpenID(c.Context(), repo.FindUserByOpenIDParams{ Openid: openid, Type: 0, }) if err == nil { return handleThirdLogin(c, openid, "", "", 0, vo) } if !errorx.IsNotFound(err) { return err } // 新用户 → 拉用户信息 nickname, avatar, err := getWechatUserInfo(accessToken, openid) if err != nil { return responsex.Error(c, "微信登录失败,请重试") } return handleThirdLogin(c, openid, nickname, avatar, 0, vo) } func getWechatAccess(code string) (openid string, accessToken string, err error) { bodyData, bodyCode, err := httpx.Get( "https://api.weixin.qq.com/sns/oauth2/access_token", client.Config{ Param: map[string]string{ "appid": config.GetConf().Wechat.AppId, "secret": config.GetConf().Wechat.AppSecret, "code": code, "grant_type": "authorization_code", }, }, ) if err != nil { return "", "", err } if bodyCode != 200 { return "", "", fmt.Errorf("微信Http请求失败: %d", bodyCode) } accessMap, err := utils.JSONStringToMap(bodyData) if err != nil { return "", "", err } accessToken, _ = accessMap["access_token"].(string) openid, _ = accessMap["openid"].(string) if accessToken == "" || openid == "" { return "", "", errors.New("获取微信登录凭证失败") } return } func getWechatUserInfo(accessToken, openid string) (nickname, avatar string, err error) { bodyData, bodyCode, err := httpx.Get( "https://api.weixin.qq.com/sns/userinfo", client.Config{ Param: map[string]string{ "access_token": accessToken, "openid": openid, }, }, ) if err != nil { return "", "", err } if bodyCode != 200 { return "", "", fmt.Errorf("微信Http请求失败") } userMap, err := utils.JSONStringToMap(bodyData) if err != nil { return "", "", err } nickname, _ = userMap["nickname"].(string) avatar, _ = userMap["headimgurl"].(string) return } func handleThirdLogin( c fiber.Ctx, openid string, nickname string, avatar string, loginType int32, // 0=微信 1=QQ vo *types.LoginVO, ) error { user, err := db.Queries.FindUserByOpenID(c.Context(), repo.FindUserByOpenIDParams{ Openid: openid, Type: loginType, }) if err != nil { if errorx.IsNotFound(err) { // 用户不存在 → 注册 return registerUser(c, openid, nickname, avatar, loginType, vo) } return err } // 用户存在 if user.Status == 0 { return responsex.Error(c, "账号已被禁用") } _ = db.Queries.UpdateUserLastLoginTime(c.Context(), user.UserID) token, err := jwtx.CreateToken(c, user.UserID) if err != nil { return err } vo.Token = token vo.UserId = user.UserID vo.Nickname = user.Nickname vo.Avatar = user.Avatar return responsex.OK(c, vo) } // 注册用户 func registerUser(c fiber.Ctx, openid, nickname, avatar string, loginType int32, vo *types.LoginVO) error { userId := uniqueid.NextId() if nickname == "" { nickname = fmt.Sprintf("用户_%d", userId) } if avatar == "" { avatar = "https://default-avatar-url.com/default.png" } err := db.WithTx(c.Context(), func(q *repo.Queries) error { // 插入用户 if err := q.InsertUser(c.Context(), repo.InsertUserParams{ ID: userId, Nickname: nickname, Avatar: avatar, Status: 1, }); err != nil { return err } // 插入第三方登录信息 if err := q.InsertUserOAuth(c.Context(), repo.InsertUserOAuthParams{ ID: uniqueid.NextId(), UserID: userId, Type: loginType, Openid: openid, }); err != nil { return err } return nil }) if err != nil { return err } token, _ := jwtx.CreateToken(c, userId) vo.Token = token vo.UserId = userId vo.Nickname = nickname vo.Avatar = avatar return responsex.OK(c, vo) }