Go web 9. OAuth2.0
OAuth
앱이나 홈페이지,게임에 회원가입을 할 때 외부 유명 사이트를 통해 회원 정보를 가져 오는 것을 OAuth라고 한다.
OAuth가 필요한 이유
-
개인정보를 보관하는데 있어서 관련 법들이 많아지고, 인력과 장비를 투자하는 것이 작은 회사는 쉽지 않다.
-
고객들도 작은 사이트를 이용 할 때마다 하나하나 회원가입을 해야하는 불편함을 덜어준다.
-
큰회사들도 OAuth를 제공함에 따라 해당 회사에 가입한 회원수를 늘리고 입지를 강화 할 수 있다.
OAuth의 동작 원리
- Client: 자원을 이용하는 사용자(user)
- Resource Owner: OAuth 사용자
- Authorization Server: OAuth 인증 서버
- Resource Server(API server): 자원을 호스팅하는 서버
OAuth 사용해보기
1. console.developers.google.com에 접속 후 인증키 받기
1) 왼쪽 메뉴에서 OAuth 동의화면을 클릭
2) 오른쪽에 프로젝트 만들기 클릭
3) 프로젝트 이름 설정 후 만들기 클릭
4) 왼쪽 메뉴에서 사용자 인증 정보로 들어간뒤 상단에 +사용자 인증 정보 만들기 클릭
5) 이름 설정하고 URI 입력
6) 승인된 리디렉션 URI에 위와같이 입력 후 만들기
7) 클라이언트 ID와 보안비밀번호 카피 해두기
8) 시스템 속성에서 환경 변수 설정하기
9) 새로 만들기로 구글 클라이언트 ID와 보안비밀번호를 각각 등록해 준다.
2. Go를 이용해 웹 페이지 생성
ex) index.html
<html>
<head>
<title>Go Oauth2.0 Test</title>
</head>
<body>
<p><a href='./auth/google/login'>Google Login</a></p>
</body>
</html>
ex) 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"
)
// oauth2 패키지를 이용해 config 생성
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"},
// userinfo.email에 억세스 하는 권한 요청하기
Endpoint: google.Endpoint,
// 구글 로그인 요청을 받으면 config를 이용해서
// 구글의 어떤 경로로 보내야 되는지 (Endpoint)가 나옴
}
// 유저가 EndPoint에 직접 접근해서 로그인 할 수 있게 리다이렉트 해줘야됨
func googleLoginHandler(w http.ResponseWriter, r *http.Request) {
state := generateStateOauthCookie(w)
// 경로가 만들어지고 리다이렉트로 calback이 왔을때 키가 맞는지 확이 할 수 있어야됨
// 유저의 브라우저 쿠키에다가 tmep키를 심고 리다이렉트로 calback이 왔을때 쿠키를 비교하는 방식
url := googleOauthConfig.AuthCodeURL(state)
// 어떤 경로로 보내야 되는지 알려줌
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
// w, r , 리다이렉트 경로 , 왜리다이렉트하는지
// 유저가 해당경로로 리다이렉트 되고 구글 로그인 폼이 뜬다.
}
func generateStateOauthCookie(w http.ResponseWriter) string {
expiration := time.Now().Add(1 * 24 * time.Hour)
// 쿠키 만료시간 설정
// 현재 시간으로 부터 하루 뒤에 만료
b := make([]byte, 16) //16바이트 어레이
rand.Read(b) // 런덤 숫자로 어레이 채우기
state := base64.URLEncoding.EncodeToString(b)
// html 인코딩 하여 스트링으로 바꾸기
cookie := &http.Cookie{Name: "oauthstate", Value: state, Expires: expiration}
// 쿠키에 인코딩한 값을 넣어줌
http.SetCookie(w, cookie)
// 쿠키를 w에 넘겨줌
return state
}
func googleAuthCallback(w http.ResponseWriter, r *http.Request) {
oauthstate, _ := r.Cookie("oauthstate") //쿠키를 읽어옴
if r.FormValue("state") != oauthstate.Value {
// 쿠키 값과 state의 값이 다를 경우
// 잘못된 요청
log.Printf("invalid google oauth state cookie: %s state:%s\n", oauthstate.Value, r.FormValue("state"))
// 로그 남기기
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
// 기본 경로로 리다이렉트
}
data, err := getGoogleUserInfo(r.FormValue("code"))
// 코드를 구글에 요청해서 userinfo를 가져온다.
if err != nil {
log.Println(err.Error()) // log와 에러를 찍음
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
// 기본 경로로 리다이렉트
return
}
fmt.Fprint(w, string(data))
// err가 없을경우 유저 정보 보내기
}
// 유저정보를 리퀘스트 하는 경로
const oauthGoogleUrlAPI = "http://www.googleapis.com/oauth2/v2/userinfo?access_token="
func getGoogleUserInfo(code string) ([]byte, error) {
token, err := googleOauthConfig.Exchange(context.Background(), code)
//config를 통해 토큰 받아오기
//Exchange로 토큰과 코드 교환
//context = 쓰래드간에 데이터를 주고받는 쓰래드세이프한 저장소
if err != nil {
return nil, fmt.Errorf("Failed to Exchange %s\n", err.Error())
// 문자열로 에러를 만듦
// 데이터를 못받았기 때문에 nil을 리턴
}
resp, err := http.Get(oauthGoogleUrlAPI + token.AccessToken)
// 유저정보를 리퀘스트하는 경로에 엑세스 토큰을 붙임
// GET을 통해 요청
if err != nil {
return nil, fmt.Errorf("Failed to Get UserInfo %s\n", err.Error())
}
return ioutil.ReadAll(resp.Body)
// resp의 데이터 반환
}
func main() {
mux := pat.New()
mux.HandleFunc("/auth/google/login", googleLoginHandler)
mux.HandleFunc("/auth/google/callback", googleAuthCallback)
n := negroni.Classic()
n.UseHandler(mux)
http.ListenAndServe(":3000", n)
}
로그인을 클릭하면 구글 로그인 창이 뜬다.
로그인 했을 때
유저 정보를 얻어옴
id만 DB에 저장해서 KEY값으로 사용하고 나머지 정보는 구글이나 페이스북 처럼 큰 회사에 요청해서 여러 정보를 가져와서 사용할 수 있다.
Author And Source
이 문제에 관하여(Go web 9. OAuth2.0), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jinzza456/Go-web-9.OAuth2.0저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)