필요한 패키지
go get golang.org/x/oauth2
go get cloud.google.com/go
index.html
<html>
<head>
<title>Go Oauth2.0 Test</title>
</head>
<body>
<p><a href='./auth/google/login'>Google Login</a></p>
</body>
</html>
main.go
package main
import (
"context"
"crypto/rand"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/pat"
"github.com/urfave/negroni"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
const portNumber = ":3000"
var googleOauthConfig = oauth2.Config{
RedirectURL: "http://localhost:3000/auth/google/callback",
ClientID: os.Getenv("GOOGLE_CLIENT_ID"),
ClientSecret: os.Getenv("GOOGLE_SECRET_KEY"),
Scopes: []string{"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: google.Endpoint,
}
func googleLoginHandler(w http.ResponseWriter, r *http.Request) {
state := generateStateOauthCookie(w)
url := googleOauthConfig.AuthCodeURL(state)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
// cookie 에 일회용 비번을 저장해서 검증
func generateStateOauthCookie(w http.ResponseWriter) string {
expiration := time.Now().Add(1 * 24 * time.Hour)
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
}
func googleAuthCallback(w http.ResponseWriter, r *http.Request) {
oauthstate, _ := r.Cookie("oauthstate")
// 쿠키값과 폼데이터의 state 가 같은지 비교
if r.FormValue("state") != oauthstate.Value {
log.Printf("invalid google oauth state cookie:%s state:%s\n", oauthstate.Value, r.FormValue("state"))
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
data, err := getGoogleUserInfo(r.FormValue("code"))
if err != nil {
log.Println(err.Error())
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
fmt.Fprint(w, string(data))
}
const oauthGoogleUrlAPI = "https://www.googleapis.com/oauth2/v2/userinfo?access_token="
func getGoogleUserInfo(code string) ([]byte, error) {
token, err := googleOauthConfig.Exchange(context.Background(), code)
if err != nil {
return nil, fmt.Errorf("Failed to Exchange %s\n", err.Error())
}
// RefreshToken 은 AccessToken 이 expired 된 경우, 다시 받을때 사용
resp, err := http.Get(oauthGoogleUrlAPI + token.AccessToken)
if err != nil {
return nil, fmt.Errorf("Failed to Get UserInfo %s\n", err.Error())
}
return ioutil.ReadAll(resp.Body)
}
func main() {
// 환경변수 설정후, 재부팅해야 값들이 정상적으로 읽혀짐
log.Println("config", os.Getenv("GOOGLE_CLIENT_ID"))
log.Println("config", os.Getenv("GOOGLE_SECRET_KEY"))
mux := pat.New()
mux.HandleFunc("/auth/google/login", googleLoginHandler)
mux.HandleFunc("/auth/google/callback", googleAuthCallback)
ng := negroni.Classic()
ng.UseHandler(mux)
http.ListenAndServe(portNumber, ng)
}
참고자료 [유투브 링크]
'GO lang > Google Oauth2' 카테고리의 다른 글
[GO] Google Oauth 설정 (0) | 2021.11.22 |
---|