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 件のコメント:
コメントを投稿