본문 바로가기

Go

golang 구글 Oauth 인증 구현

1. OAuth Applciation 등록

GCP Console (https://console.cloud.google.com/)

 

외부를 클릭하여 만들고 앱 이름 , 사용자 지원 이메일, 개발자 연락처 정보만 기입하고 나머지는 빈칸으로 둔다.

그 후 사용자 인증정보를 OAuth 클라이언트 ID 를 선택해서 생성한다.

테스트 해볼 용도이니 출처는 localhost:5000 으로 리디렉션도 마찬가지로 localhost:5000/auth/google/callback 으로 했다.

이때 생성되는 클라이언트 ID 비밀번호를 잘 보관하자 이 키를 기반으로 구글인증을 진행할수 있다.

 

2. golang handler 작성

이제는 위의 저장된 정보를 기반으로 고 핸들러를 작성해보자.

현재 쓰고있는 프레임워크는 긴이라 긴으로 작성했지만 이건 쓰고있는 프레임워크를 선택하면 된다.

구글인증을 사용하기 위해선 아래와같은 패키지 설치가 필요하다.

go get -u github.com/gin-gonic/gin
go get golang.org/x/oauth2
go get cloud.google.com/go

 

main.go 

func main() {

   r := gin.Default()

   r.GET("/", googleForm)
   r.GET("/auth/google/login", googleLoginHandler)
   r.GET("/auth/google/callback", googleAuthCallback)

   r.Run(":5000")
}

구현한 핸들러는 3개 테스트로 작성해서 모든 함수가 main package 에 있지만 알맞게 라우팅을 해서 고도화 하면 된다. 

 

func googleForm(c *gin.Context) {
   c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(
      "<html>" +
         "\n<head>\n    " +
         "<title>Go Oauth2.0 Test</title>\n" +
         "</head>\n" +
         "<body>\n<p>" +
         "<a href='./auth/google/login'>Google Login</a>" +
         "</p>\n" +
         "</body>\n" +
      "</html>"))
}

localhost:5000/ 으로 들어가면

간단한 Google Login 버튼을 구현한 html 사이트가 나오고 이 버튼을 누르면

localhost:5000/auth/google/login -> 즉 googleLoginHandler 를 실행하게 된다.

var googleOauthConfig = oauth2.Config{
   RedirectURL:  "http://localhost:3000/auth/google/callback",
   ClientID:     "위에서 발급받은 ID",
   ClientSecret: "위에서 발급받은 Secret",
   Scopes:       []string{"https://www.googleapis.com/auth/userinfo.email"},
   Endpoint:     google.Endpoint,
}

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 googleLoginHandler(c *gin.Context) {

   state := generateStateOauthCookie(c.Writer)
   url := googleOauthConfig.AuthCodeURL(state)
   c.Redirect(http.StatusTemporaryRedirect,url)
}

이제 googleLoginHandler 를 작성할 차례다.
state : 패키지로 받은 AuthCodeURL 함수에 인자로 들어가는 값이다. 베이스64인코딩을 해주고 쿠기로 저장한다.

 

url : 패키지를 받은 googleOauthConfig.AuthCodeURL(state) 를 실행하게 되면 

구글에서 Config 에 들어있는 값 기반으로 인증을 한후 우리에게 url 을 전달해주고 우리는 다시 거기로 redirect 를 보낸다. 

url 은 https://accounts.google.com/o/oauth2/auth 뒤에 client_id 와 scope , state 등 필수정보를 포함한

query 값을 보내주는데 이걸 들어가면 아래와 같은 구글 로그인 화면이 나온다.

 

이제 저기서 구글 로그인을 하면 위에서 설정한 승인된 Redirection URI 로 정보를 받아와야 한다.
googleAuthCallback 핸들러가 그역할을 하는데 아래 코드다.
(localhost:5000/auth/google/callback)

 

func googleAuthCallback(c *gin.Context) {


   oauthstate, _ := c.Request.Cookie("oauthstate") // 12

   if c.Request.FormValue("state") != oauthstate.Value { // 13
      log.Printf("invalid google oauth state cookie:%s state:%s\n", oauthstate.Value, c.Request.FormValue("state"))
      c.Redirect(http.StatusTemporaryRedirect,"/")
      return
   }

   data, err := getGoogleUserInfo(c.Request.FormValue("code")) // 14
   if err != nil {                                     // 15
      log.Println(err.Error())
      c.Redirect( http.StatusTemporaryRedirect,"/")
      return
   }

   fmt.Fprint(c.Writer, string(data)) // 16
}

func getGoogleUserInfo(code string) ([]byte, error) { // 17

   token, err := googleOauthConfig.Exchange(context.Background(), code) // 18
   if err != nil {                                                      // 19
      return nil, fmt.Errorf("Failed to Exchange %s\n", err.Error())
   }

   resp, err := http.Get(oauthGoogleUrlAPI + token.AccessToken) // 20
   if err != nil {                                              // 21
      return nil, fmt.Errorf("Failed to Get UserInfo %s\n", err.Error())
   }

   return ioutil.ReadAll(resp.Body) // 23
}

우리가 state 를 위에서 생성한 후 쿠키에 저장을 해놨다가 Callback 함수가 실행됐을때 그정보를 response 값이랑 비교를 해서 같은지 확인한후 받아온 code 값으로 .Exchange 함수를 사용해서 Token 값을 가져올 수 있다.

 

우리는 이 토큰 값으로 JWT 을 생성해서 관리하거나 필요에 따라 맞게 활용 할 수 있다.
위의 코드는 구글이 토큰값으로 인증한 후에 오는 데이터값을 반환하는데 JSON 형식으로

id , email , verified_email , picture 를 반환한다.

 

POST 

https://www.googleapis.com/oauth2/v3/userinfo?access_token=[토큰값]  을 주면 아래와 같은 데이터를 가져오게 된다.

 

{
  "id": "186",
  "email": "myungsworld@gmail.com",
  "verified_email": true,
  "picture": "https://lh3.googleusercontent.com/a-/AOhGbjsc=s96-c"
}

 

이상 구글 Oauth2 인증을 구현해봤다.