15357fd3c0
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
125 lines
4.2 KiB
Go
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
|
|
} |