Files
schisandra-album-cloud-micr…/app/auth/api/internal/logic/oauth/qq_callback_logic.go
2024-12-24 18:01:54 +08:00

267 lines
7.1 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 oauth
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
model2 "schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"strconv"
"strings"
"github.com/yitter/idgenerator-go/idgen"
"gorm.io/gorm"
"github.com/zeromicro/go-zero/core/logx"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
)
type QqCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
type AuthQQme struct {
ClientID string `json:"client_id"`
OpenID string `json:"openid"`
}
type QQToken struct {
AccessToken string `json:"access_token"`
ExpireIn string `json:"expire_in"`
RefreshToken string `json:"refresh_token"`
}
type QQUserInfo struct {
City string `json:"city"`
Figureurl string `json:"figureurl"`
Figureurl1 string `json:"figureurl_1"`
Figureurl2 string `json:"figureurl_2"`
FigureurlQq string `json:"figureurl_qq"`
FigureurlQq1 string `json:"figureurl_qq_1"`
FigureurlQq2 string `json:"figureurl_qq_2"`
Gender string `json:"gender"`
GenderType int `json:"gender_type"`
IsLost int `json:"is_lost"`
IsYellowVip string `json:"is_yellow_vip"`
IsYellowYearVip string `json:"is_yellow_year_vip"`
Level string `json:"level"`
Msg string `json:"msg"`
Nickname string `json:"nickname"`
Province string `json:"province"`
Ret int `json:"ret"`
Vip string `json:"vip"`
Year string `json:"year"`
YellowVipLevel string `json:"yellow_vip_level"`
}
func NewQqCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QqCallbackLogic {
return &QqCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QqCallbackLogic) QqCallback(r *http.Request, req *types.OAuthCallbackRequest) (string, error) {
tokenAuthUrl := l.GetQQTokenAuthUrl(req.Code)
token, err := l.GetQQToken(tokenAuthUrl)
if err != nil {
return "", err
}
if token == nil {
return "", errors.New("get qq token failed")
}
// 通过 token 获取 openid
authQQme, err := l.GetQQUserOpenID(token)
if err != nil {
return "", err
}
// 通过 token 和 openid 获取用户信息
userInfo, err := l.GetQQUserUserInfo(token, authQQme.OpenID)
if err != nil {
return "", err
}
if userInfo == nil {
return "", errors.New("get qq user info failed")
}
// 处理用户信息
userInfoBytes, err := json.Marshal(userInfo)
if err != nil {
return "", err
}
var qqUserInfo QQUserInfo
err = json.Unmarshal(userInfoBytes, &qqUserInfo)
if err != nil {
return "", err
}
tx := l.svcCtx.DB.Begin()
userSocial := l.svcCtx.DB.ScaAuthUserSocial
socialUser, err := tx.ScaAuthUserSocial.Where(userSocial.OpenID.Eq(authQQme.OpenID), userSocial.Source.Eq(constant.OAuthSourceQQ)).First()
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return "", err
}
if socialUser == nil {
// 创建用户
uid := idgen.NextId()
uidStr := strconv.FormatInt(uid, 10)
male := constant.Male
avatarUrl := strings.Replace(qqUserInfo.FigureurlQq1, "http://", "https://", 1)
addUser := &model2.ScaAuthUser{
UID: uidStr,
Avatar: avatarUrl,
Username: authQQme.OpenID,
Nickname: qqUserInfo.Nickname,
Gender: male,
}
err = tx.ScaAuthUser.Create(addUser)
if err != nil {
_ = tx.Rollback()
return "", err
}
githubUser := constant.OAuthSourceQQ
newSocialUser := &model2.ScaAuthUserSocial{
UserID: uidStr,
OpenID: authQQme.OpenID,
Source: githubUser,
}
err = tx.ScaAuthUserSocial.Create(newSocialUser)
if err != nil {
_ = tx.Rollback()
return "", err
}
if res, err := l.svcCtx.CasbinEnforcer.AddRoleForUser(uidStr, constant.User); !res || err != nil {
_ = tx.Rollback()
return "", err
}
data, err := HandleOauthLoginResponse(addUser, l.svcCtx, r, l.ctx)
if err != nil {
_ = tx.Rollback()
return "", err
}
if err = tx.Commit(); err != nil {
return "", err
}
return data, nil
} else {
authUser := l.svcCtx.DB.ScaAuthUser
authUserInfo, err := tx.ScaAuthUser.Where(authUser.UID.Eq(socialUser.UserID)).First()
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
_ = tx.Rollback()
return "", err
}
data, err := HandleOauthLoginResponse(authUserInfo, l.svcCtx, r, l.ctx)
if err != nil {
_ = tx.Rollback()
return "", err
}
if err = tx.Commit(); err != nil {
return "", err
}
return data, nil
}
}
// GetQQTokenAuthUrl 通过code获取token认证url
func (l *QqCallbackLogic) GetQQTokenAuthUrl(code string) string {
clientId := l.svcCtx.Config.OAuth.QQ.ClientID
clientSecret := l.svcCtx.Config.OAuth.QQ.ClientSecret
redirectURI := l.svcCtx.Config.OAuth.QQ.RedirectURI
return fmt.Sprintf(
"https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s&fmt=json",
clientId, clientSecret, code, redirectURI,
)
}
// GetQQToken 获取 token
func (l *QqCallbackLogic) GetQQToken(url string) (*QQToken, error) {
// 形成请求
var req *http.Request
var err error
if req, err = http.NewRequest(http.MethodGet, url, nil); err != nil {
return nil, err
}
// 发送请求并获得响应
var httpClient = http.Client{}
var res *http.Response
if res, err = httpClient.Do(req); err != nil {
return nil, err
}
// 将响应体解析为 token并返回
var token QQToken
if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
return nil, err
}
return &token, nil
}
// GetQQUserOpenID 获取用户 openid
func (l *QqCallbackLogic) GetQQUserOpenID(token *QQToken) (*AuthQQme, error) {
// 形成请求
var userInfoUrl = "https://graph.qq.com/oauth2.0/me?access_token=" + token.AccessToken + "&fmt=json"
var req *http.Request
var err error
if req, err = http.NewRequest(http.MethodGet, userInfoUrl, nil); err != nil {
return nil, err
}
// 发送请求并获取响应
var client = http.Client{}
var res *http.Response
if res, err = client.Do(req); err != nil {
return nil, err
}
// 将响应体解析为 AuthQQme并返回
var authQQme AuthQQme
if err = json.NewDecoder(res.Body).Decode(&authQQme); err != nil {
return nil, err
}
return &authQQme, nil
}
// GetQQUserUserInfo 获取用户信息
func (l *QqCallbackLogic) GetQQUserUserInfo(token *QQToken, openId string) (map[string]interface{}, error) {
clientId := l.svcCtx.Config.OAuth.QQ.ClientID
// 形成请求
var userInfoUrl = "https://graph.qq.com/user/get_user_info?access_token=" + token.AccessToken + "&oauth_consumer_key=" + clientId + "&openid=" + openId
var req *http.Request
var err error
if req, err = http.NewRequest(http.MethodGet, userInfoUrl, nil); err != nil {
return nil, err
}
// 发送请求并获取响应
var client = http.Client{}
var res *http.Response
if res, err = client.Do(req); err != nil {
return nil, err
}
// 将响应的数据写入 userInfo 中,并返回
var userInfo = make(map[string]interface{})
if err = json.NewDecoder(res.Body).Decode(&userInfo); err != nil {
return nil, err
}
return userInfo, nil
}