Files
tp/main_dc/yalarba/api_tp/internal/handlers/oauth_VK.go
T
valitovgaziz 15357fd3c0 create and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and
yalarba
2025-10-24 05:22:44 +05:00

125 lines
4.2 KiB
Go

package handlers
import (
"encoding/json"
"fmt"
"net/http"
"api_tp/internal/config"
"api_tp/internal/utils"
)
// VKUserInfo представляет данные пользователя от VK
type VKUserInfo struct {
Response []struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Photo string `json:"photo_200"`
} `json:"response"`
}
// VKEmailResponse представляет ответ с email от VK
type VKEmailResponse struct {
Email string `json:"email"`
}
// VKLogin initiates VK OAuth flow
func (h *OAuthHandler) VKLogin(w http.ResponseWriter, r *http.Request) {
url := config.VKOAuthConfig.AuthCodeURL("state")
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
// VKCallback handles VK OAuth callback
func (h *OAuthHandler) VKCallback(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
token, err := config.VKOAuthConfig.Exchange(r.Context(), code)
if err != nil {
utils.WriteError(w, http.StatusBadRequest, "Failed to exchange token: "+err.Error())
return
}
// VK не возвращает email в основном токене, нужно получить его отдельно
email, err := h.getVKEmail(token.AccessToken)
if err != nil {
utils.WriteError(w, http.StatusBadRequest, "Failed to get email from VK: "+err.Error())
return
}
client := config.VKOAuthConfig.Client(r.Context(), token)
// Получаем основную информацию о пользователе
userInfoURL := fmt.Sprintf("https://api.vk.com/method/users.get?fields=photo_200,email&v=5.131&access_token=%s", token.AccessToken)
resp, err := client.Get(userInfoURL)
if err != nil {
utils.WriteError(w, http.StatusBadRequest, "Failed to get user info: "+err.Error())
return
}
defer resp.Body.Close()
var vkUserInfo VKUserInfo
if err := json.NewDecoder(resp.Body).Decode(&vkUserInfo); err != nil {
utils.WriteError(w, http.StatusBadRequest, "Failed to decode user info: "+err.Error())
return
}
if len(vkUserInfo.Response) == 0 {
utils.WriteError(w, http.StatusBadRequest, "No user data received from VK")
return
}
vkUser := vkUserInfo.Response[0]
userID := fmt.Sprintf("%d", vkUser.ID)
name := vkUser.FirstName + " " + vkUser.LastName
// Используем email из отдельного запроса
if email == "" && vkUser.Email != "" {
email = vkUser.Email
}
// Если email все еще пустой, создаем временный
if email == "" {
email = fmt.Sprintf("vk_%s@temp.vk", userID)
}
// Создаем или находим пользователя
user, err := h.findOrCreateOAuthUser("vk", userID, email, name, token)
if err != nil {
utils.WriteError(w, http.StatusInternalServerError, "Error processing user: "+err.Error())
return
}
jwtToken, err := utils.GenerateJWT(user.ID, user.Email)
if err != nil {
utils.WriteError(w, http.StatusInternalServerError, "Error generating token: "+err.Error())
return
}
h.handleOAuthSuccess(w, r, jwtToken, user)
}
// getVKEmail получает email из VK OAuth
func (h *OAuthHandler) getVKEmail(accessToken string) (string, error) {
// VK возвращает email в ответе на запрос токена, но если его нет,
// можно попробовать получить через API
emailURL := fmt.Sprintf("https://api.vk.com/method/account.getProfileInfo?v=5.131&access_token=%s", accessToken)
resp, err := http.Get(emailURL)
if err != nil {
return "", err
}
defer resp.Body.Close()
var emailResp struct {
Response struct {
Email string `json:"email"`
} `json:"response"`
}
if err := json.NewDecoder(resp.Body).Decode(&emailResp); err != nil {
return "", err
}
return emailResp.Response.Email, nil
}