Skip to content

Commit

Permalink
Merge pull request #51 from NJUPT-SAST/dev-clients
Browse files Browse the repository at this point in the history
Add third platform login and modify login flow
  • Loading branch information
Xunop authored Oct 14, 2023
2 parents 7c74ca0 + 43365f1 commit 609adb8
Show file tree
Hide file tree
Showing 20 changed files with 630 additions and 152 deletions.
106 changes: 106 additions & 0 deletions api/v1/oauth_client_github.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package v1

import (
"context"
"fmt"
"io"
"net/http"

"github.com/NJUPT-SAST/sast-link-backend/config"
"github.com/NJUPT-SAST/sast-link-backend/endpoints"
"github.com/NJUPT-SAST/sast-link-backend/model/result"
"github.com/NJUPT-SAST/sast-link-backend/service"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"golang.org/x/oauth2"
)

const (
// GitHub user info url
GithubUserInfoURL = "https://api.github.com/user"
)

var (
githubConf = oauth2.Config{
ClientID: config.Config.GetString("oauth.client.github.id"),
ClientSecret: config.Config.GetString("oauth.client.github.secret"),
RedirectURL: config.Config.GetString("oauth.client.github.redirect_url"),
Scopes: []string{},
Endpoint: endpoints.GitHub,
}
)

func OauthGithubLogin(c *gin.Context) {

// Create oauthState cookie
oauthState := GenerateStateOauthCookie(c.Writer)
url := githubConf.AuthCodeURL(oauthState)

fmt.Println("------")
fmt.Printf("Visit the URL for the auth dialog: %v\n", url)
fmt.Println("------")

c.Redirect(http.StatusFound, url)
}

func OauthGithubCallback(c *gin.Context) {
oauthState, _ := c.Request.Cookie("oauthstate")

if c.Request.FormValue("state") != oauthState.Value {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthState.Value, c.Request.FormValue("state"))
c.Redirect(http.StatusFound, "/")
return
}

code := c.Query("code")

githubId, err := getUserInfoFromGithub(c.Request.Context(), code)
if err != nil {
c.JSON(http.StatusOK, result.Failed(result.HandleError(err)))
return
}

if githubId == "" {
c.JSON(http.StatusOK, result.Failed(result.HandleError(result.RequestParamError)))
return
}

user, err := service.GetUserByGithubId(githubId)
if err != nil {
c.JSON(http.StatusOK, result.Failed(result.HandleError(err)))
return
}

// User not found, Need to register to bind the github id
if user == nil {
return
}

c.JSON(http.StatusOK, result.Success(githubId))
}

func getUserInfoFromGithub(ctx context.Context, code string) (string, error) {

token, err := githubConf.Exchange(ctx, code)
if err != nil {
return "", fmt.Errorf("exchange github code error: %s", err.Error())
}
client := &http.Client{}
req, err := http.NewRequest("GET", GithubUserInfoURL, nil)
if err != nil {
return "", fmt.Errorf("new request error: %s", err.Error())
}
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
res, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("failt to getting user info: %s", err.Error())
}
body, err := io.ReadAll(res.Body)
if err != nil {
return "", result.InternalErr
}

// Now just get the github id
githubId := gjson.Get(string(body), "id").String()
return githubId, nil
}
135 changes: 135 additions & 0 deletions api/v1/oauth_client_lark.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package v1

import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
"time"

"github.com/NJUPT-SAST/sast-link-backend/config"
"github.com/NJUPT-SAST/sast-link-backend/endpoints"
"github.com/NJUPT-SAST/sast-link-backend/log"
"github.com/NJUPT-SAST/sast-link-backend/model"
"github.com/NJUPT-SAST/sast-link-backend/model/result"
"github.com/NJUPT-SAST/sast-link-backend/util"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"golang.org/x/oauth2"
)

const (
AppAccessTokenURL = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal"
UserAccessTokenURL = "https://open.feishu.cn/open-apis/authen/v1/oidc/access_token"
)

var (
larkConf = oauth2.Config{
ClientID: config.Config.GetString("oauth.client.lark.id"),
ClientSecret: config.Config.GetString("oauth.client.lark.secret"),
RedirectURL: "http://localhost:8080/api/v1/login/lark/callback",
Scopes: []string{},
Endpoint: endpoints.Lark,
}
)

// OauthLarkLogin redirect url to lark auth page.
func OauthLarkLogin(c *gin.Context) {
url := larkConf.AuthCodeURL("state")

log.Log.Warnf("Visit the URL for the auth dialog: %v\n", url)

c.Redirect(http.StatusPermanentRedirect, url)
}

// OauthLarkCallback read url from lark callback,
// get `code`, request app_access_token,
// at last request lark url to get user_access_token.
func OauthLarkCallback(c *gin.Context) {
code := c.Query("code")
log.Log.Debugf("\ncode ::: %s\n", code)
accessToken, err := getLarkAppAccessToken()

if err != nil {
log.Log.Errorln("getLarkAppAccessToken ::: ", err)
c.JSON(http.StatusInternalServerError, result.Failed(result.HandleError(err)))
return
}

data := map[string]string {
"grant_type": "authorization_code",
"code": code,
}

header := map[string]string {
"Authorization": fmt.Sprintf("Bearer %s", accessToken),
"Content-Type": "application/json; charset=utf-8",
}

res, err := util.PostWithHeader(UserAccessTokenURL, header, data)
if err != nil {
log.Log.Errorln("util.PostWithHeader ::: ", err)
c.JSON(http.StatusOK, result.Failed(result.HandleError(result.AccessTokenErr)))
}

body, err := io.ReadAll(res.Body)
defer res.Body.Close()
if err != nil {
log.Log.Errorln("io.ReadAll ::: ", err)
c.JSON(http.StatusInternalServerError, result.Failed(result.HandleError(err)))
return
}
if resCode := gjson.Get(string(body), "code").Int(); resCode != 0 {
log.Log.Errorf("gjson.Get ::: response code: %d\n", resCode)
c.JSON(http.StatusOK, result.Failed(result.HandleError(errors.New(fmt.Sprintf("OauthLarkCallback resCode: %d", resCode)))))
return
}

userAccessToken := gjson.Get(string(body), "data.access_token").String()
expire := gjson.Get(string(body), "data.expire_in").Int()

model.Rdb.Set(model.RedisCtx, "lark_user_access_token", userAccessToken, time.Duration(expire))
c.JSON(http.StatusOK, data)

}

// Get Lark app_access_token
func getLarkAppAccessToken() (string, error) {
appId := larkConf.ClientID
appSecret := larkConf.ClientSecret

params := url.Values{}
params.Add("app_id", appId)
params.Add("app_secret", appSecret)

res, error := http.PostForm(AppAccessTokenURL, params)
if error != nil {
log.Log.Errorln("http.PostForm ::: ", error)
return "", error
}
log.LogRes(res)

body, error := io.ReadAll(res.Body)
defer res.Body.Close()
if error != nil {
log.Log.Errorln("io.ReadAll ::: ", error)
return "", error
}


if code := gjson.Get(string(body), "code").Int(); code != 0 {
log.Log.Errorln("gjson.Get ::: code:", code)
return "", result.InternalErr
}

acceToken := gjson.Get(string(body), "app_access_token").String()
expire := gjson.Get(string(body), "expire").Int()

model.Rdb.Set(model.RedisCtx, "lark_app_access_token", acceToken, time.Duration(expire))

return acceToken, nil
}


func getUserInfo(user_access_token string) {}
20 changes: 20 additions & 0 deletions api/v1/oauth_clients.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package v1

import (
"crypto/rand"
"encoding/base64"
"net/http"
"time"
)

func GenerateStateOauthCookie(w http.ResponseWriter) string {
var expiration = time.Now().Add(20 * time.Minute)

b := make([]byte, 16)
rand.Read(b)
state := base64.URLEncoding.EncodeToString(b)
cookie := http.Cookie{Name: "oauthstate", Value: state, Expires: expiration}
http.SetCookie(w, &cookie)

return state
}
32 changes: 16 additions & 16 deletions api/v1/oauth.go → api/v1/oauth_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (

var (
srv *server.Server
pgxConn, _ = pgx.Connect(context.TODO(), config.Config.Sub("oauth").GetString("db_uri"))
pgxConn, _ = pgx.Connect(context.TODO(), config.Config.Sub("oauth.server").GetString("db_uri"))
adapter = pgx4adapter.NewConn(pgxConn)
clientStore, _ = pg.NewClientStore(adapter)
)
Expand Down Expand Up @@ -184,21 +184,21 @@ func Authorize(c *gin.Context) {
}

// User decides whether to authorize
func UserAuth(c *gin.Context) {
w := c.Writer
r := c.Request

//token := r.Header.Get("TOKEN")
_ = r.ParseMultipartForm(0)
token := c.PostForm("token")
if token == "" {
w.Header().Set("Content-Type", "application/json")
response := result.Failed(result.TokenError)
json, _ := json.Marshal(response)
w.Write(json)
return
}
}
// func UserAuth(c *gin.Context) {
// w := c.Writer
// r := c.Request
//
// //token := r.Header.Get("TOKEN")
// _ = r.ParseMultipartForm(0)
// token := c.PostForm("token")
// if token == "" {
// w.Header().Set("Content-Type", "application/json")
// response := result.Failed(result.AuthError)
// json, _ := json.Marshal(response)
// w.Write(json)
// return
// }
// }

// Get AccessToken
func AccessToken(c *gin.Context) {
Expand Down
Loading

0 comments on commit 609adb8

Please sign in to comment.