update oauth to use oauth2 library
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
parent
c3bf4a3d6f
commit
cb126da5d9
|
|
@ -1 +1,59 @@
|
||||||
package oauth
|
package oauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/github"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type githubOauth2 struct {
|
||||||
|
baseOauth2
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGithubOauth2(name string, clientID string, clientSecret string, db *gorm.DB) (Oauther, error) {
|
||||||
|
|
||||||
|
oa := &githubOauth2{}
|
||||||
|
oa.Name = name
|
||||||
|
oa.Config = &oauth2.Config{
|
||||||
|
ClientID: clientID,
|
||||||
|
ClientSecret: clientSecret,
|
||||||
|
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
|
||||||
|
"https://www.googleapis.com/auth/userinfo.email"},
|
||||||
|
Endpoint: github.Endpoint,
|
||||||
|
}
|
||||||
|
oa.UserInfoURL = "https://api.github.com/user"
|
||||||
|
|
||||||
|
redirectURL, err := oa.GetRediectURL(db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
oa.Config.RedirectURL = redirectURL
|
||||||
|
return oa, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oa *githubOauth2) GetOauthUserInfo(token string) (*oauth2User, error) {
|
||||||
|
req, err := http.NewRequest("GET", oa.UserInfoURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "token"+" "+token)
|
||||||
|
response, err := (&http.Client{}).Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
contents, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := oauth2User{}
|
||||||
|
err = json.Unmarshal(contents, &u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &u, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,28 @@
|
||||||
package oauth
|
package oauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type googleOauth2 struct {
|
type googleOauth2 struct {
|
||||||
oauth2
|
baseOauth2
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGoogle(name string, clientID string, clientSecret string, scopes string, authURL string, tokenURL string, db *gorm.DB) (*oauth, error) {
|
func NewGoogleOauth2(name string, clientID string, clientSecret string, db *gorm.DB) (Oauther, error) {
|
||||||
|
|
||||||
oa := &googleOauth2{
|
oa := &googleOauth2{}
|
||||||
Name: name,
|
oa.Name = name
|
||||||
Config: &oauth2.Config{
|
oa.Config = &oauth2.Config{
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
ClientSecret: clientSecret,
|
ClientSecret: clientSecret,
|
||||||
Scopes: strings.Split(scopes, ","),
|
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
|
||||||
Endpoint: google.
|
"https://www.googleapis.com/auth/userinfo.email"},
|
||||||
},
|
Endpoint: google.Endpoint,
|
||||||
}
|
}
|
||||||
|
oa.UserInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
|
||||||
|
|
||||||
redirectURL, err := oa.GetRediectURL(db)
|
redirectURL, err := oa.GetRediectURL(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,42 @@
|
||||||
package oauth
|
package oauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"d7y.io/dragonfly/v2/manager/model"
|
"d7y.io/dragonfly/v2/manager/model"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type oauth2 struct {
|
type baseOauth2 struct {
|
||||||
Name string
|
Name string
|
||||||
UserInfoURL string
|
UserInfoURL string
|
||||||
Config *oauth2.Config
|
Config *oauth2.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type oauth2User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
// oauth interface
|
// oauth interface
|
||||||
type Oauther interface {
|
type Oauther interface {
|
||||||
GetRediectURL(*gorm.DB) (string, error)
|
GetRediectURL(*gorm.DB) (string, error)
|
||||||
GetOauthUserInfo(string) (*model.User, error)
|
GetOauthUserInfo(string) (*oauth2User, error)
|
||||||
|
ExchangeUserByCode(string, *gorm.DB) (*model.User, error)
|
||||||
|
AuthCodeURL(string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOauth(name string, clientID string, clientSecret string, scopes string, authURL string, tokenURL string, db *gorm.DB) (*oauth, error) {
|
func NewBaseOauth2(name string, clientID string, clientSecret string, scopes string, authURL string, tokenURL string, db *gorm.DB) (Oauther, error) {
|
||||||
|
|
||||||
oa := &oauth2{
|
oa := &baseOauth2{
|
||||||
Name: name,
|
Name: name,
|
||||||
Config: &oauth2.Config{
|
Config: &oauth2.Config{
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
|
|
@ -43,7 +56,7 @@ func NewOauth(name string, clientID string, clientSecret string, scopes string,
|
||||||
return oa, nil
|
return oa, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *oauth2) GetRediectURL(db *gorm.DB) (string, error) {
|
func (oa *baseOauth2) GetRediectURL(db *gorm.DB) (string, error) {
|
||||||
|
|
||||||
s := model.Settings{}
|
s := model.Settings{}
|
||||||
if err := db.First(&s, model.Settings{
|
if err := db.First(&s, model.Settings{
|
||||||
|
|
@ -51,10 +64,74 @@ func (o *oauth2) GetRediectURL(db *gorm.DB) (string, error) {
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s/api/v1/oauth/%s/sigin", s.Value, o.Name), nil
|
return fmt.Sprintf("%s/api/v1/oauth/%s/sigin", s.Value, oa.Name), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *oauth2) GetOauthUserInfo(code string) (*model.User, error) {
|
func (oa *baseOauth2) AuthCodeURL(state string) string {
|
||||||
user := model.User{}
|
return oa.Config.AuthCodeURL(state)
|
||||||
return &user, nil
|
}
|
||||||
|
|
||||||
|
func (oa *baseOauth2) GetOauthUserInfo(token string) (*oauth2User, error) {
|
||||||
|
response, err := http.Get(fmt.Sprintf("%s?access_token=%s", oa.UserInfoURL, token))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
contents, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := oauth2User{}
|
||||||
|
err = json.Unmarshal(contents, &u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oa *baseOauth2) ExchangeUserByCode(code string, db *gorm.DB) (*model.User, error) {
|
||||||
|
token, err := oa.Config.Exchange(context.Background(), code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if oa.UserInfoURL == "" {
|
||||||
|
return nil, errors.New("UserInfoURL is empty")
|
||||||
|
}
|
||||||
|
u, err := oa.GetOauthUserInfo(token.AccessToken)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Name == "admin" {
|
||||||
|
return nil, errors.New("admin is not allowed to login by oauth")
|
||||||
|
}
|
||||||
|
encryptedPasswordBytes, err := bcrypt.GenerateFromPassword([]byte("Dragonfly2"), bcrypt.MinCost)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var userCount int64
|
||||||
|
if err := db.Model(model.User{}).Where("name = ?", u.Name).Count(&userCount).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if userCount <= 0 {
|
||||||
|
user := model.User{
|
||||||
|
EncryptedPassword: string(encryptedPasswordBytes),
|
||||||
|
Name: u.Name,
|
||||||
|
Email: u.Email,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Create(&user).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &user, nil
|
||||||
|
|
||||||
|
} else {
|
||||||
|
user := model.User{}
|
||||||
|
if err := db.Model(model.User{}).Where("name = ?", u.Name).First(&user).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,11 +95,11 @@ func (s *rest) OauthSignin(name string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := oauth.NewOauth(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
|
o, err := oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return o.Config.AuthCodeURL("state"), nil
|
return o.AuthCodeURL("state"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *rest) OauthCallback(name, code string) (*model.User, error) {
|
func (s *rest) OauthCallback(name, code string) (*model.User, error) {
|
||||||
|
|
@ -108,11 +108,11 @@ func (s *rest) OauthCallback(name, code string) (*model.User, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := oauth.NewOauth(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
|
o, err := oauth.NewBaseOauth2(name, oauthModel.ClientID, oauthModel.ClientSecret, oauthModel.Scopes, oauthModel.AuthURL, oauthModel.TokenURL, s.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user, err := o.GetOauthUserInfo(code)
|
user, err := o.ExchangeUserByCode(code, s.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue