mirror of https://gitee.com/answerdev/answer.git
feat(plugin): google connector
This commit is contained in:
parent
154fa84bbb
commit
1664eb7d16
|
@ -1,7 +1,5 @@
|
|||
package plugin
|
||||
|
||||
import "time"
|
||||
|
||||
type Connector interface {
|
||||
Base
|
||||
|
||||
|
@ -26,25 +24,20 @@ type Connector interface {
|
|||
ConnectorSender(ctx *GinContext)
|
||||
ConnectorReceiver(ctx *GinContext)
|
||||
|
||||
//ConnectorLoginURL() (loginURL string)
|
||||
//ConnectorLoginUserInfo(code string) (userInfo *UserExternalLogin)
|
||||
//ConnectorLoginURL(redirectURL string) (loginURL string)
|
||||
//ConnectorLoginUserInfo(code string) (userInfo *UserExternalLogin, err error)
|
||||
}
|
||||
|
||||
type UserExternalLogin struct {
|
||||
Provider string
|
||||
ExternalID string
|
||||
Email string
|
||||
Name string
|
||||
FirstName string
|
||||
LastName string
|
||||
NickName string
|
||||
Description string
|
||||
AvatarUrl string
|
||||
Location string
|
||||
AccessToken string
|
||||
AccessTokenSecret string
|
||||
RefreshToken string
|
||||
ExpiresAt time.Time
|
||||
Provider string
|
||||
ExternalID string
|
||||
Email string
|
||||
Name string
|
||||
FirstName string
|
||||
LastName string
|
||||
NickName string
|
||||
Description string
|
||||
AvatarUrl string
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -46,7 +46,7 @@ func (g *GitHub) ConnectorLogoContentType() string {
|
|||
}
|
||||
|
||||
func (g *GitHub) ConnectorName() string {
|
||||
return "GitHubConnector"
|
||||
return "GitHub"
|
||||
}
|
||||
|
||||
func (g *GitHub) ConnectorSlugName() string {
|
||||
|
@ -58,39 +58,88 @@ func (g *GitHub) ConnectorSender(ctx *plugin.GinContext) {
|
|||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2GitHub.Endpoint,
|
||||
RedirectURL: "http://127.0.0.1:8080/answer/api/v1/oauth/redirect/github",
|
||||
RedirectURL: "http://127.0.0.1:8080/answer/api/v1/oauth/redirect/github", // TODO: Pass by parameter
|
||||
Scopes: nil,
|
||||
}
|
||||
ctx.Redirect(http.StatusFound, oauth2Config.AuthCodeURL(""))
|
||||
ctx.Redirect(http.StatusFound, oauth2Config.AuthCodeURL("state"))
|
||||
}
|
||||
|
||||
func (g *GitHub) ConnectorReceiver(ctx *plugin.GinContext) {
|
||||
code := ctx.Query("code")
|
||||
//state := ctx.Query("state")
|
||||
|
||||
// Exchange code for token
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2GitHub.Endpoint,
|
||||
}
|
||||
token, err := oauth2Config.Exchange(context.Background(), code+"1")
|
||||
token, err := oauth2Config.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
return
|
||||
}
|
||||
|
||||
// Exchange token for user info
|
||||
cli := github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token.AccessToken},
|
||||
)))
|
||||
userInfo, _, err := cli.Users.Get(context.Background(), "")
|
||||
if err != nil {
|
||||
ctx.Error(err)
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("user info is :%+v", userInfo)
|
||||
ctx.Redirect(http.StatusFound, "/")
|
||||
// TODO
|
||||
// If user email exists, try to login this user.
|
||||
// If user email not exists, try to register this user.
|
||||
|
||||
ctx.Redirect(http.StatusFound, "/login-success?access_token=token")
|
||||
return
|
||||
}
|
||||
|
||||
func (g *GitHub) ConnectorLoginURL(redirectURL, state string) (loginURL string) {
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2GitHub.Endpoint,
|
||||
RedirectURL: redirectURL,
|
||||
}
|
||||
return oauth2Config.AuthCodeURL(state)
|
||||
}
|
||||
|
||||
func (g *GitHub) ConnectorLoginUserInfo(code string) (userInfo *plugin.UserExternalLogin, err error) {
|
||||
// Exchange code for token
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2GitHub.Endpoint,
|
||||
}
|
||||
token, err := oauth2Config.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Exchange token for user info
|
||||
cli := github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token.AccessToken},
|
||||
)))
|
||||
resp, _, err := cli.Users.Get(context.Background(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userInfo = &plugin.UserExternalLogin{
|
||||
Provider: g.ConnectorSlugName(),
|
||||
ExternalID: fmt.Sprintf("%d", resp.GetID()),
|
||||
Email: resp.GetEmail(),
|
||||
Name: resp.GetName(),
|
||||
FirstName: resp.GetName(),
|
||||
LastName: resp.GetName(),
|
||||
NickName: resp.GetName(),
|
||||
Description: resp.GetBio(),
|
||||
AvatarUrl: resp.GetAvatarURL(),
|
||||
}
|
||||
return userInfo, nil
|
||||
}
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
package connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/plugin"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"golang.org/x/oauth2"
|
||||
oauth2Google "golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
type Google struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugin.Register(&Google{
|
||||
ClientID: os.Getenv("GOOGLE_CLIENT_ID"),
|
||||
ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
|
||||
})
|
||||
}
|
||||
|
||||
func (g *Google) Info() plugin.Info {
|
||||
|
@ -18,7 +36,11 @@ func (g *Google) Info() plugin.Info {
|
|||
}
|
||||
|
||||
func (g *Google) ConnectorLogo() []byte {
|
||||
return nil
|
||||
response, err := resty.New().R().Get("https://cdn-icons-png.flaticon.com/32/300/300221.png")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return response.Body()
|
||||
}
|
||||
|
||||
func (g *Google) ConnectorLogoContentType() string {
|
||||
|
@ -26,7 +48,7 @@ func (g *Google) ConnectorLogoContentType() string {
|
|||
}
|
||||
|
||||
func (g *Google) ConnectorName() string {
|
||||
return "google"
|
||||
return "Google"
|
||||
}
|
||||
|
||||
func (g *Google) ConnectorSlugName() string {
|
||||
|
@ -34,14 +56,68 @@ func (g *Google) ConnectorSlugName() string {
|
|||
}
|
||||
|
||||
func (g *Google) ConnectorSender(ctx *plugin.GinContext) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2Google.Endpoint,
|
||||
RedirectURL: "http://127.0.0.1:8080/answer/api/v1/oauth/redirect/google", // TODO: Pass by parameter
|
||||
Scopes: []string{
|
||||
"https://www.googleapis.com/auth/userinfo.email",
|
||||
"https://www.googleapis.com/auth/userinfo.profile",
|
||||
"openid",
|
||||
},
|
||||
}
|
||||
ctx.Redirect(http.StatusFound, oauth2Config.AuthCodeURL("state"))
|
||||
}
|
||||
|
||||
type GoogleAuthUserInfo struct {
|
||||
Sub string `json:"sub"`
|
||||
Name string `json:"name"`
|
||||
GivenName string `json:"given_name"`
|
||||
FamilyName string `json:"family_name"`
|
||||
Profile string `json:"profile"`
|
||||
Picture string `json:"picture"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
Gender string `json:"gender"`
|
||||
}
|
||||
|
||||
func (g *Google) ConnectorReceiver(ctx *plugin.GinContext) {
|
||||
ctx.String(http.StatusOK, "OK123")
|
||||
}
|
||||
code := ctx.Query("code")
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2Google.Endpoint,
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugin.Register(&Google{})
|
||||
token, err := oauth2Config.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
return
|
||||
}
|
||||
|
||||
client := oauth2Config.Client(context.TODO(), token)
|
||||
client.Timeout = 60 * time.Second
|
||||
userinfo, err := client.Get("https://www.googleapis.com/oauth2/v3/userinfo")
|
||||
if err != nil {
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
return
|
||||
}
|
||||
defer userinfo.Body.Close()
|
||||
data, _ := io.ReadAll(userinfo.Body)
|
||||
|
||||
userInfo := &GoogleAuthUserInfo{}
|
||||
if err = json.Unmarshal(data, userInfo); err != nil {
|
||||
ctx.Redirect(http.StatusFound, "/50x")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("user info is :%+v", userInfo)
|
||||
|
||||
// TODO
|
||||
// If user email exists, try to login this user.
|
||||
// If user email not exists, try to register this user.
|
||||
|
||||
ctx.Redirect(http.StatusFound, "/login-success?access_token=token")
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue