feat(plugin): google connector

This commit is contained in:
LinkinStar 2023-01-04 17:33:19 +08:00
parent 154fa84bbb
commit 1664eb7d16
3 changed files with 151 additions and 33 deletions

View File

@ -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 (

View File

@ -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
}

View File

@ -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
}