Dockerでローカル環境を楽に整えつつ、GAEをベースにしたアプリ開発ができれば最高だなあ。と常々思っていたので、今回はそれについて書きつつ、実践的なGoogleOAuth認証のアプリを作っていきたいと思います。
すぐにでもコードを見たい方はこちらをどうぞ。
GAEとdepのDocker環境を整える
まずは DockerCompose をインストールしましょう。
公式サイトを参考にインストールしてください。
インストールできたら次はDockerイメージとComposeファイルを用意します。
今回はGAEベースのアプリケーションを作りたいので、mercariさんが提供してくれているGEAのDockerイメージを利用します。
加えて、ベンダリングのツールには「dep」を利用するので、いい感じのDockerイメージを探してきてComposeファイルに追加します。
version: '2'
services:
app:
image: mercari/appengine-go:1.8
working_dir: /go/src/github.com/gotokatsuya/gae-google
command: make serve-dev
ports:
- 8080:8080
- 8000:8000
volumes:
- .:/go/src/github.com/gotokatsuya/gae-google
dep:
image: instrumentisto/dep:0.3.2
working_dir: /go/src/github.com/gotokatsuya/gae-google
volumes:
- .:/go/src/github.com/gotokatsuya/gae-google
このようなdocker-compose.ymlを用意するだけでローカル開発が最高に楽になります。
GoogleOAuth認証アプリを作る
GoogleOAuth認証設定
コードを書く前にGoogleOAuthの設定をして、ClientIDとClientSecretを取得、そしてRedirectURLをセットします。設定方法は公式サイトが参考になります。
今回のアプリケーションではRedirectURLはhttp://localhost:8080/auth/google/callback
を指定してください。ClientIDとClientSecretはapp.yamlに環境変数として記載します。
application: gae-google
version: 1
runtime: go
api_version: go1.8
handlers:
- url: /.*
script: _go_app
secure: always
env_variables:
AUTH_GOOGLE_CLIENT_ID: "xxx"
AUTH_GOOGLE_CLIENT_SECRET: "xxx"
AUTH_GOOGLE_REDIRECT_URL: "http://localhost:8080/auth/google/callback"
実際にコードを書いていく
まずはRoutingから作ります。
package routes
import (
"net/http"
"github.com/gorilla/mux"
"github.com/urfave/negroni"
"github.com/gotokatsuya/gae-google/app/controllers"
)
var (
App = negroni.New(negroni.NewRecovery())
)
func init() {
router := mux.NewRouter()
authRouter := router.PathPrefix("/auth").Subrouter()
authRouter.Path("/login").HandlerFunc(controllers.AuthLoginHandler).Methods(http.MethodGet)
authRouter.Path("/google").HandlerFunc(controllers.AuthGoogleHandler).Methods(http.MethodGet)
authRouter.Path("/google/callback").HandlerFunc(controllers.AuthGoogleCallbackHandler).Methods(http.MethodGet)
App.UseHandler(router)
}
Contollerを作っていきます。
package controllers
import (
"net/http"
"google.golang.org/appengine"
"github.com/gotokatsuya/gae-google/lib/template"
"github.com/gotokatsuya/gae-google/app/services/auth"
)
// AuthLoginHandler HTMLをレンダリングする
func AuthLoginHandler(w http.ResponseWriter, r *http.Request) {
template.Render.HTML(w, http.StatusOK, "auth/login", nil)
}
// AuthGoogleHandler Googleログイン
func AuthGoogleHandler(w http.ResponseWriter, r *http.Request) {
svc := auth.NewService()
// ランダム値を生成する
state := svc.GenerateState()
// CallbackするURLを生成する
url := svc.GoogleAuthURL(state)
// 生成したランダム値ををセッションに保存する
svc.SaveState(state, r, w)
http.Redirect(w, r, url, http.StatusFound)
}
// AuthGoogleCallbackHandler Googleログイン認証結果
func AuthGoogleCallbackHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
svc := auth.NewService()
// セッションに保存されているランダム値と比較して一致するかどうか確認
if r.URL.Query().Get("state") != svc.State(r) {
http.Error(w, "invalid state", http.StatusUnauthorized)
return
}
// GoogleログインしたユーザーのメールアドレスやIDを取得する
if err := svc.GoogleLogin(ctx, r.URL.Query().Get("code")); err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
// 適当な画面に飛ばす
http.Redirect(w, r, "https://eure.jp", http.StatusFound)
}
DockerComposeを使って起動する
最初に記載したように今回はdepを使って依存ライブラリをベンダリングします。今回はvendorフォルダをgit管理しているので実行する必要はないですが、initを実行するとvendorフォルダが作られ、ライブラリをベンダリングしてくれるようになります。
// $ docker-compose run --rm dep init
GAEに載せるアプリケーションを起動します。
$ docker-compose up app
起動後に http://localhost:8080/auth/login へアクセスするとこのようなシンプルな画面がレンダリングされるはずです。
「Google Login」ボタンを押下するとログイン画面が立ち上がります。ログインに成功すると、適当に設定したeurekaのHPに遷移します。