ペペロミア開発ブログ

React Nativeで開発しているアプリ「ペペロミア」の技術系記事を投稿してます

GAE/Go 2nd-genでfirebase Authを実装してみる

ログイン機能を作ろうと思ったのでGAE/Goで実装してみた

GAE/Go 2nd-genとは

cloud.google.com

2nd-genの変更点は、ここでまとめられるので読むと分かるかも

github.com

実装

公式のサンプルがあるので、これを元に作成

github.com

app.yaml

■app.yaml

runtime: go111

「runtime: go111」で使えるようになります

取り敢えず、動くものをデプロイしてみる

■app.go

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run()
}

ローカルで確認

$ dev_appserver.py app.yaml

確認

$ curl http://localhost:8080/ping
{"message":"pong"}

動いているを確認したらデプロイ。。。 する前にvgoで依存管理をする

$ export GO111MODULE=on
$ go mod init
$ go mod vendor

これで、「vendor」フォルダにmoduleが入る

これでデプロイ

$ gcloud app deploy

これでAPIとして利用可能になった

firebase Authを実装

あとはfirebase Authの実装を追加

まずMiddlewareを書く

■ middleware/firebase.go

package middleware

import (
    "context"
    "net/http"
    "os"
    "strings"

    firebase "firebase.google.com/go"
    "github.com/gin-gonic/gin"
    "golang.org/x/oauth2/google"
    "google.golang.org/api/option"
)

func FirebaseAuthMiddleWare(gc *gin.Context) {
    ctx := context.Background()
    creds, err := google.CredentialsFromJSON(ctx, []byte(os.Getenv("FIREBASE_SERVICE_ACCOUNT_JSON")))
    if err != nil {
        gc.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    opt := option.WithCredentials(creds)
    app, err := firebase.NewApp(context.Background(), nil, opt)
    if err != nil {
        gc.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    auth, err := app.Auth(context.Background())
    if err != nil {
        gc.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    idToken := strings.Replace(gc.GetHeader("Authorization"), "Bearer ", "", 1)
    _, err = auth.VerifyIDToken(context.Background(), idToken)
    if err != nil {
        gc.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    gc.Next()
}

環境変数にfirebaseの設定を追加

■app.yaml

runtime: go111

env_variables:
  FIREBASE_SERVICE_ACCOUNT_JSON: |
    {
      "type": "**************",
      "project_id": "**************",
      "private_key_id": "**************",
      "private_key": "**************",
      "client_email": "**************",
      "client_id": "**************",
      "auth_uri": "**************",
      "token_uri": "**************",
      "auth_provider_x509_cert_url": "**************",
      "client_x509_cert_url": "**************"
    }
    

最後にcorsとmiddlewareの設定を追加して完了

■app.go

package main

import (
    "net/http"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
    "github.com/wheatandcat/Peperomia/backend/handler"
    "github.com/wheatandcat/Peperomia/backend/middleware"
)

func main() {
    r := gin.Default()

    r.Use(cors.New(cors.Config{
        AllowOrigins: []string{"https://foo.com"},
        AllowMethods: []string{
            http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodOptions,
        },
        AllowHeaders: []string{
            "Authorization",
            "Content-Type",
            "Cache-Control",
        },
        AllowCredentials: true,
        MaxAge:           86400,
    }))

    r.Use(middleware.FirebaseAuthMiddleWare)

    h := handler.NewHandler()

    r.POST("/SaveUser", h.SaveUser)
    r.Run()
}

これで取り敢えず、認証してAPIアクセスのができるはず、 次回はフロント側の実装の紹介をしようと思います。

今回の修正のpull request

Firebaseログインを追加する by wheatandcat · Pull Request #12 · wheatandcat/Peperomia · GitHub