🏗️ microservice fabric splitting
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
)
|
||||
|
||||
type GetGiteeOauthUrlLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetGiteeOauthUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetGiteeOauthUrlLogic {
|
||||
return &GetGiteeOauthUrlLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetGiteeOauthUrlLogic) GetGiteeOauthUrl() (resp string, err error) {
|
||||
clientID := l.svcCtx.Config.OAuth.Gitee.ClientID
|
||||
redirectURI := l.svcCtx.Config.OAuth.Gitee.RedirectURI
|
||||
url := "https://gitee.com/oauth/authorize?client_id=" + clientID + "&redirect_uri=" + redirectURI + "&response_type=code"
|
||||
return url, nil
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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 GetGithubOauthUrlLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetGithubOauthUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetGithubOauthUrlLogic {
|
||||
return &GetGithubOauthUrlLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetGithubOauthUrlLogic) GetGithubOauthUrl(req *types.OAuthRequest) (resp string, err error) {
|
||||
clientId := l.svcCtx.Config.OAuth.Github.ClientID
|
||||
redirectUrl := l.svcCtx.Config.OAuth.Github.RedirectURI
|
||||
url := "https://github.com/login/oauth/authorize?client_id=" + clientId + "&redirect_uri=" + redirectUrl + "&state=" + req.State
|
||||
return url, nil
|
||||
}
|
29
app/auth/api/internal/logic/oauth/get_qq_oauth_url_logic.go
Normal file
29
app/auth/api/internal/logic/oauth/get_qq_oauth_url_logic.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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 GetQqOauthUrlLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetQqOauthUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetQqOauthUrlLogic {
|
||||
return &GetQqOauthUrlLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetQqOauthUrlLogic) GetQqOauthUrl(req *types.OAuthRequest) (resp string, err error) {
|
||||
clientId := l.svcCtx.Config.OAuth.QQ.ClientID
|
||||
redirectURI := l.svcCtx.Config.OAuth.QQ.RedirectURI
|
||||
url := "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=" + clientId + "&redirect_uri=" + redirectURI + "&state=" + req.State
|
||||
return url, nil
|
||||
}
|
262
app/auth/api/internal/logic/oauth/gitee_callback_logic.go
Normal file
262
app/auth/api/internal/logic/oauth/gitee_callback_logic.go
Normal file
@@ -0,0 +1,262 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/model/mysql/model"
|
||||
"schisandra-album-cloud-microservices/common/constant"
|
||||
"schisandra-album-cloud-microservices/common/xhttp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/yitter/idgenerator-go/idgen"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/user"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
|
||||
)
|
||||
|
||||
type GiteeCallbackLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
type GiteeUser struct {
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Bio string `json:"bio"`
|
||||
Blog string `json:"blog"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Email string `json:"email"`
|
||||
EventsURL string `json:"events_url"`
|
||||
Followers int `json:"followers"`
|
||||
FollowersURL string `json:"followers_url"`
|
||||
Following int `json:"following"`
|
||||
FollowingURL string `json:"following_url"`
|
||||
GistsURL string `json:"gists_url"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
ID int `json:"id"`
|
||||
Login string `json:"login"`
|
||||
Name string `json:"name"`
|
||||
OrganizationsURL string `json:"organizations_url"`
|
||||
PublicGists int `json:"public_gists"`
|
||||
PublicRepos int `json:"public_repos"`
|
||||
ReceivedEventsURL string `json:"received_events_url"`
|
||||
Remark string `json:"remark"`
|
||||
ReposURL string `json:"repos_url"`
|
||||
Stared int `json:"stared"`
|
||||
StarredURL string `json:"starred_url"`
|
||||
SubscriptionsURL string `json:"subscriptions_url"`
|
||||
Type string `json:"type"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
URL string `json:"url"`
|
||||
Watched int `json:"watched"`
|
||||
Weibo interface{} `json:"weibo"`
|
||||
}
|
||||
type Token struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
|
||||
var Script = `
|
||||
<script>
|
||||
window.opener.postMessage('%s', '%s');
|
||||
window.close();
|
||||
</script>
|
||||
`
|
||||
|
||||
func NewGiteeCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GiteeCallbackLogic {
|
||||
return &GiteeCallbackLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GiteeCallbackLogic) GiteeCallback(r *http.Request, req *types.OAuthCallbackRequest) (string, error) {
|
||||
// 获取 token
|
||||
tokenAuthUrl := l.GetGiteeTokenAuthUrl(req.Code)
|
||||
token, err := l.GetGiteeToken(tokenAuthUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if token == nil {
|
||||
return "", errors.New("get gitee token failed")
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
userInfo, err := l.GetGiteeUserInfo(token)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if userInfo == nil {
|
||||
return "", errors.New("get gitee user info failed")
|
||||
}
|
||||
|
||||
var giteeUser GiteeUser
|
||||
marshal, err := json.Marshal(userInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = json.Unmarshal(marshal, &giteeUser); err != nil {
|
||||
return "", err
|
||||
}
|
||||
Id := strconv.Itoa(giteeUser.ID)
|
||||
|
||||
tx := l.svcCtx.DB.Begin()
|
||||
|
||||
userSocial := l.svcCtx.DB.ScaAuthUserSocial
|
||||
socialUser, err := tx.ScaAuthUserSocial.Where(userSocial.OpenID.Eq(Id), userSocial.Source.Eq(constant.OAuthSourceGitee)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if socialUser == nil {
|
||||
// 创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
addUser := &model.ScaAuthUser{
|
||||
UID: uidStr,
|
||||
Avatar: giteeUser.AvatarURL,
|
||||
Username: giteeUser.Login,
|
||||
Nickname: giteeUser.Name,
|
||||
Blog: giteeUser.Blog,
|
||||
Email: giteeUser.Email,
|
||||
Gender: constant.Male,
|
||||
}
|
||||
err = tx.ScaAuthUser.Create(addUser)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return "", err
|
||||
}
|
||||
gitee := constant.OAuthSourceGitee
|
||||
newSocialUser := &model.ScaAuthUserSocial{
|
||||
UserID: uidStr,
|
||||
OpenID: Id,
|
||||
Source: gitee,
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// HandleOauthLoginResponse 处理登录响应
|
||||
func HandleOauthLoginResponse(scaAuthUser *model.ScaAuthUser, svcCtx *svc.ServiceContext, r *http.Request, ctx context.Context) (string, error) {
|
||||
data, err := user.HandleLoginJWT(scaAuthUser, svcCtx, true, r, ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
marshalData, err := json.Marshal(xhttp.BaseResponse[*types.LoginResponse]{
|
||||
Data: data,
|
||||
Code: 200,
|
||||
Msg: "success",
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
formattedScript := fmt.Sprintf(Script, marshalData, svcCtx.Config.Web.URL)
|
||||
return formattedScript, nil
|
||||
}
|
||||
|
||||
// GetGiteeTokenAuthUrl 获取Gitee token
|
||||
func (l *GiteeCallbackLogic) GetGiteeTokenAuthUrl(code string) string {
|
||||
clientId := l.svcCtx.Config.OAuth.Gitee.ClientID
|
||||
clientSecret := l.svcCtx.Config.OAuth.Gitee.ClientSecret
|
||||
redirectURI := l.svcCtx.Config.OAuth.Gitee.RedirectURI
|
||||
return fmt.Sprintf(
|
||||
"https://gitee.com/oauth/token?grant_type=authorization_code&code=%s&client_id=%s&redirect_uri=%s&client_secret=%s",
|
||||
code, clientId, redirectURI, clientSecret,
|
||||
)
|
||||
}
|
||||
|
||||
// GetGiteeToken 获取 token
|
||||
func (l *GiteeCallbackLogic) GetGiteeToken(url string) (*Token, error) {
|
||||
|
||||
// 形成请求
|
||||
var req *http.Request
|
||||
var err error
|
||||
if req, err = http.NewRequest(http.MethodPost, url, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("accept", "application/json")
|
||||
|
||||
// 发送请求并获得响应
|
||||
var httpClient = http.Client{}
|
||||
var res *http.Response
|
||||
if res, err = httpClient.Do(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将响应体解析为 token,并返回
|
||||
var token Token
|
||||
if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// GetGiteeUserInfo 获取用户信息
|
||||
func (l *GiteeCallbackLogic) GetGiteeUserInfo(token *Token) (map[string]interface{}, error) {
|
||||
|
||||
// 形成请求
|
||||
var userInfoUrl = "https://gitee.com/api/v5/user" // github用户信息获取接口
|
||||
var req *http.Request
|
||||
var err error
|
||||
if req, err = http.NewRequest(http.MethodGet, userInfoUrl, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("accept", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("token %s", token.AccessToken))
|
||||
// 发送请求并获取响应
|
||||
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
|
||||
}
|
244
app/auth/api/internal/logic/oauth/github_callback_logic.go
Normal file
244
app/auth/api/internal/logic/oauth/github_callback_logic.go
Normal file
@@ -0,0 +1,244 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/model/mysql/model"
|
||||
"schisandra-album-cloud-microservices/common/constant"
|
||||
"strconv"
|
||||
|
||||
"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 GithubCallbackLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
type GitHubUser struct {
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Bio interface{} `json:"bio"`
|
||||
Blog string `json:"blog"`
|
||||
Company interface{} `json:"company"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Email string `json:"email"`
|
||||
EventsURL string `json:"events_url"`
|
||||
Followers int `json:"followers"`
|
||||
FollowersURL string `json:"followers_url"`
|
||||
Following int `json:"following"`
|
||||
FollowingURL string `json:"following_url"`
|
||||
GistsURL string `json:"gists_url"`
|
||||
GravatarID string `json:"gravatar_id"`
|
||||
Hireable interface{} `json:"hireable"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
ID int `json:"id"`
|
||||
Location interface{} `json:"location"`
|
||||
Login string `json:"login"`
|
||||
Name string `json:"name"`
|
||||
NodeID string `json:"node_id"`
|
||||
NotificationEmail interface{} `json:"notification_email"`
|
||||
OrganizationsURL string `json:"organizations_url"`
|
||||
PublicGists int `json:"public_gists"`
|
||||
PublicRepos int `json:"public_repos"`
|
||||
ReceivedEventsURL string `json:"received_events_url"`
|
||||
ReposURL string `json:"repos_url"`
|
||||
SiteAdmin bool `json:"site_admin"`
|
||||
StarredURL string `json:"starred_url"`
|
||||
SubscriptionsURL string `json:"subscriptions_url"`
|
||||
TwitterUsername interface{} `json:"twitter_username"`
|
||||
Type string `json:"type"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
func NewGithubCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GithubCallbackLogic {
|
||||
return &GithubCallbackLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GithubCallbackLogic) GithubCallback(r *http.Request, req *types.OAuthCallbackRequest) (string, error) {
|
||||
|
||||
// 获取 token
|
||||
tokenAuthUrl := l.GetTokenAuthUrl(req.Code)
|
||||
token, err := l.GetToken(tokenAuthUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if token == nil {
|
||||
|
||||
return "", errors.New("get github token failed")
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
userInfo, err := l.GetUserInfo(token)
|
||||
if err != nil {
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
if userInfo == nil {
|
||||
return "", errors.New("get github user info failed")
|
||||
}
|
||||
|
||||
// 处理用户信息
|
||||
userInfoBytes, err := json.Marshal(userInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var gitHubUser GitHubUser
|
||||
err = json.Unmarshal(userInfoBytes, &gitHubUser)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
Id := strconv.Itoa(gitHubUser.ID)
|
||||
tx := l.svcCtx.DB.Begin()
|
||||
|
||||
userSocial := l.svcCtx.DB.ScaAuthUserSocial
|
||||
socialUser, err := tx.ScaAuthUserSocial.Where(userSocial.OpenID.Eq(Id), userSocial.Source.Eq(constant.OAuthSourceGithub)).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
|
||||
addUser := &model.ScaAuthUser{
|
||||
UID: uidStr,
|
||||
Avatar: gitHubUser.AvatarURL,
|
||||
Username: gitHubUser.Login,
|
||||
Nickname: gitHubUser.Name,
|
||||
Blog: gitHubUser.Blog,
|
||||
Email: gitHubUser.Email,
|
||||
|
||||
Gender: male,
|
||||
}
|
||||
err = tx.ScaAuthUser.Create(addUser)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return "", err
|
||||
}
|
||||
githubUser := constant.OAuthSourceGithub
|
||||
newSocialUser := &model.ScaAuthUserSocial{
|
||||
UserID: uidStr,
|
||||
OpenID: Id,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// GetTokenAuthUrl 通过code获取token认证url
|
||||
func (l *GithubCallbackLogic) GetTokenAuthUrl(code string) string {
|
||||
clientId := l.svcCtx.Config.OAuth.Github.ClientID
|
||||
clientSecret := l.svcCtx.Config.OAuth.Github.ClientSecret
|
||||
return fmt.Sprintf(
|
||||
"https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s",
|
||||
clientId, clientSecret, code,
|
||||
)
|
||||
}
|
||||
|
||||
// GetToken 获取 token
|
||||
func (l *GithubCallbackLogic) GetToken(url string) (*Token, error) {
|
||||
|
||||
// 形成请求
|
||||
var req *http.Request
|
||||
var err error
|
||||
if req, err = http.NewRequest(http.MethodGet, url, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("accept", "application/json")
|
||||
|
||||
// 发送请求并获得响应
|
||||
var httpClient = http.Client{}
|
||||
var res *http.Response
|
||||
if res, err = httpClient.Do(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将响应体解析为 token,并返回
|
||||
var token Token
|
||||
if err = json.NewDecoder(res.Body).Decode(&token); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// GetUserInfo 获取用户信息
|
||||
func (l *GithubCallbackLogic) GetUserInfo(token *Token) (map[string]interface{}, error) {
|
||||
|
||||
// 形成请求
|
||||
var userInfoUrl = "https://api.github.com/user" // github用户信息获取接口
|
||||
var req *http.Request
|
||||
var err error
|
||||
if req, err = http.NewRequest(http.MethodGet, userInfoUrl, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("accept", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("token %s", token.AccessToken))
|
||||
|
||||
// 发送请求并获取响应
|
||||
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
|
||||
}
|
266
app/auth/api/internal/logic/oauth/qq_callback_logic.go
Normal file
266
app/auth/api/internal/logic/oauth/qq_callback_logic.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/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 := &model.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 := &model.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
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/contract"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/messages"
|
||||
models2 "github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/models"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount/server/handlers/models"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/websocket"
|
||||
"schisandra-album-cloud-microservices/common/encrypt"
|
||||
"schisandra-album-cloud-microservices/common/i18n"
|
||||
"schisandra-album-cloud-microservices/common/xhttp"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
)
|
||||
|
||||
type WechatOffiaccountCallbackLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
type MessageData struct {
|
||||
Openid string `json:"openid"`
|
||||
ClientId string `json:"client_id"`
|
||||
}
|
||||
|
||||
func NewWechatOffiaccountCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatOffiaccountCallbackLogic {
|
||||
return &WechatOffiaccountCallbackLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *WechatOffiaccountCallbackLogic) WechatOffiaccountCallback(r *http.Request) (*http.Response, error) {
|
||||
rs, err := l.svcCtx.WechatOfficial.Server.Notify(r, func(event contract.EventInterface) interface{} {
|
||||
switch event.GetMsgType() {
|
||||
case models2.CALLBACK_MSG_TYPE_EVENT:
|
||||
switch event.GetEvent() {
|
||||
case models.CALLBACK_EVENT_SUBSCRIBE:
|
||||
msg := models.EventSubscribe{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
logx.Error(err.Error())
|
||||
return "error"
|
||||
}
|
||||
key := strings.TrimPrefix(msg.EventKey, "qrscene_")
|
||||
err = l.SendMessage(msg.FromUserName, key)
|
||||
if err != nil {
|
||||
return messages.NewText(i18n.FormatText(l.ctx, "login.loginFailed"))
|
||||
}
|
||||
return messages.NewText(i18n.FormatText(l.ctx, "login.loginSuccess"))
|
||||
|
||||
case models.CALLBACK_EVENT_UNSUBSCRIBE:
|
||||
msg := models.EventUnSubscribe{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
logx.Error(err.Error())
|
||||
return "error"
|
||||
}
|
||||
return messages.NewText("ok")
|
||||
|
||||
case models.CALLBACK_EVENT_SCAN:
|
||||
msg := models.EventScan{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
logx.Error(err.Error())
|
||||
return "error"
|
||||
}
|
||||
err = l.SendMessage(msg.FromUserName, msg.EventKey)
|
||||
if err != nil {
|
||||
return messages.NewText(i18n.FormatText(l.ctx, "login.loginFailed"))
|
||||
}
|
||||
return messages.NewText(i18n.FormatText(l.ctx, "login.loginSuccess"))
|
||||
|
||||
}
|
||||
|
||||
case models2.CALLBACK_MSG_TYPE_TEXT:
|
||||
msg := models.MessageText{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
logx.Error(err.Error())
|
||||
return "error"
|
||||
}
|
||||
}
|
||||
return messages.NewText("ok")
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// SendMessage 发送消息到客户端
|
||||
func (l *WechatOffiaccountCallbackLogic) SendMessage(openId string, clientId string) error {
|
||||
encryptClientId, err := encrypt.Encrypt(clientId, l.svcCtx.Config.Encrypt.Key, l.svcCtx.Config.Encrypt.IV)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encryptOpenId, err := encrypt.Encrypt(openId, l.svcCtx.Config.Encrypt.Key, l.svcCtx.Config.Encrypt.IV)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
messageData := MessageData{
|
||||
Openid: encryptOpenId,
|
||||
ClientId: encryptClientId,
|
||||
}
|
||||
jsonData, err := json.Marshal(xhttp.BaseResponse[MessageData]{
|
||||
Code: 200,
|
||||
Data: messageData,
|
||||
Msg: "success",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = websocket.QrcodeWebSocketHandler.SendMessageToClient(clientId, jsonData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
)
|
||||
|
||||
type WechatOffiaccountCallbackVerifyLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewWechatOffiaccountCallbackVerifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatOffiaccountCallbackVerifyLogic {
|
||||
return &WechatOffiaccountCallbackVerifyLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *WechatOffiaccountCallbackVerifyLogic) WechatOffiaccountCallbackVerify(r *http.Request) (*http.Response, error) {
|
||||
rs, err := l.svcCtx.WechatOfficial.Server.VerifyURL(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs, nil
|
||||
}
|
Reference in New Issue
Block a user