GAE + Go で Sign in with Facebook
続いて実際にコードを書いていきます。
ちなみに今回は OAuth 2.0 の認証コード方式を使います。
まずログインボタンを設置します。
ボタンの画像はサードパーティから無料で提供されているものを使用しました。
リンク先を /login_facebook とします。
<a href="/login_facebook"><img src="/client/login/img/sign_in_with_facebook.png"></a>
/login_facebook に対応するハンドラを作成します。
http.HandleFunc から呼び出します。
// Facebook のログインボタンが押された時の処理
func (this *Controller) LoginFacebook(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
oauth := NewOAuth2(c, FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET)
oauth.RequestAuthorizationCode(w, r, "https://www.facebook.com/dialog/oauth", url.QueryEscape("http://escape-3ds.appspot.com/callback_facebook"))
}
Facebook から発行された Client ID とClient Secret を使って通信します。
最初に、アプリがユーザデータへアクセスする許可をユーザから得る必要があります。
Facebook ではユーザの許可を得る画面を OAuth Dialog と読んでいます。
OAuth Dialog の URL は http://www.facebook.com/dialog/oauth です。
ここに Client ID, Client Secret, 許可をもらった時のリダイレクト URL を GET で渡します。
詳しくはこちらをご覧ください
OAuth Dialog - Facebook Developers
中身はこんな感じになっています。
// OAuth 2.0
type OAuth2 struct {
context appengine.Context
clientId string
clientSecret string
}
// OAuth2.0 インスタンスを返す
func NewOAuth2(c appengine.Context, clientId string, clientSecret string) *OAuth2 {
oauth := new(OAuth2)
oauth.context = c
oauth.clientId = clientId
oauth.clientSecret = clientSecret
return oauth
}
// 認証コードをリクエストする
// 認証ページヘのリダイレクトを行いユーザに認証してもらう
// 認証が完了したらリダイレクトURIへ認証コードが返ってくる
func (this *OAuth2) RequestAuthorizationCode(w http.ResponseWriter, r *http.Request, targetUri string, redirectUri string) {
targetUri = fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&response_type=code", targetUri, this.clientId, redirectUri)
http.Redirect(w, r, targetUri, 302)
}
今回はリダイレクト先として http://escape-3ds.appspot.com/callback_facebook を設定しました。
自分のアプリに合わせてコールバック先の URL を設定してください。
コールバックされた後の処理を書きます。
こちらも http.HandleFunc() で呼び出されるようにしましょう。
// Facebook でユーザがアクセスを許可した時に呼び出されるコールバック関数
func (this *Controller) CallbackFacebook(w http.ResponseWriter, r*http.Request) {
c := appengine.NewContext(r)
userInfo := this.RequestFacebookToken(w, r)
model := NewModel(c)
view := NewView(c, w)
key := ""
if model.ExistOAuthUser("Facebook", userInfo["oauth_id"]) {
// 既存ユーザ
params := make(map[string]string, 2)
params["OAuthId"] = userInfo["oauth_id"]
params["Type"] = "Facebook"
key = model.GetUserKey(params)
} else {
// 新規ユーザ
params := make(map[string]string, 4)
params["user_type"] = "Facebook"
params["user_name"] = userInfo["name"]
params["user_oauth_id"] = userInfo["oauth_id"]
params["user_pass"] = ""
user := model.NewUser(params)
key = model.AddUser(user)
}
if this.GetSession(c, r) == "" {
this.StartSession(w, r, key)
}
view.Gamelist(key)
}
ユーザからの許可が得られたら、アクセストークンを Facebook に要求します。
上のコードでは RequestFacebookToken() で要求しています。
このとき、ユーザIDとユーザ名が含まれたレスポンスが Facebook から返されます。
データベース上にユーザID が存在するかどうかを調べて、新規ユーザかどうかを判断しています。
アクセストークンの取得先 URL は https://graph.facebook.com/oauth/access_token です。
アクセストークンについてはこちら
Access Tokens - Facebook Developer
RequestFacebookToken() の中身はこんな感じ。
// Facebook へアクセストークンを要求する。
// この関数は Facebook から認証コードをリダイレクトで渡された時に呼ばれる。
// ユーザ情報を格納した map を返す。
func (this *Controller) RequestFacebookToken(w http.ResponseWriter, r *http.Request) map[string]string {
c := appengine.NewContext(r)
code := r.FormValue("code")
oauth := NewOAuth2(c, FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET)
token := oauth.RequestAccessToken(w, r, "https://graph.facebook.com/oauth/access_token", url.QueryEscape("http://escape-3ds.appspot.com/callback_facebook"), code)
response := oauth.RequestAPI(w, "https://graph.facebook.com/me", token)
// JSON を解析
type UserInfo struct {
Id string `json:"id"`
Name string `json:"name"`
}
userInfo := new(UserInfo)
err := json.Unmarshal(response, userInfo)
Check(c, err)
result := make(map[string]string, 2)
result["oauth_id"] = userInfo.Id
result["name"] = userInfo.Name
return result
}
RequestAccessToken() でアクセストークンとユーザ情報を取得して、
レスポンスのユーザデータのパースしています。
RequestAccessToken() の中身はこんな感じ。
// アクセストークンをリクエストする
// 引き換えとして認証コードを渡すこと
func (this *OAuth2) RequestAccessToken(w http.ResponseWriter, r *http.Request, targetUri string, redirectUri string, code string) string {
targetUri = fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&client_secret=%s&code=%s", targetUri, this.clientId, redirectUri, this.clientSecret, code)
params := make(map[string]string, 4)
params["client_id"] = this.clientId
params["redirect_uri"] = redirectUri
params["client_secret"] = this.clientSecret
params["code"] = code
response := Request(this.context, "GET", targetUri, params, "")
body := make([]byte, 1024)
_, err := response.Body.Read(body)
Check(this.context, err)
// response: oauth_token=******&expires=******
responseParams := strings.Split(string(body), "&")
tokenParam := strings.Split(responseParams[0], "=")
return tokenParam[1]
}
すべてのコードは GitHub においてあります。
https://github.com/yokano/escape3ds
OAuth 2.0 に関するコントローラは
server/controller/controller.go
server/controller/oauth.go
ライブラリは
server/lib/oauth2.go
にあります。


0 件のコメント:
コメントを投稿