🚪
gRPCとFirebase Authenticationで認証処理
はじめに
gRPCとFirebase Authenticationを使用したGoサーバでの認証処理のやり方を紹介します。認可処理についてはまた別記事で書く予定です。
Firebase Authentication
SDKの追加は以下のコマンドからできます。
go get firebase.google.com/go
Firebase Admin SDK for Go の初期化は以下を参考にします。
サーバーに Firebase Admin SDK を追加する
従来はoption.WithCredentialsFile()
を使用した初期化が一般的だったようですが、GOOGLE_APPLICATION_CREDENTIALS 環境変数を使用する初期化を強くお勧めしているようです。
firebase.go
package middleware
import (
"context"
firebase "firebase.google.com/go"
"firebase.google.com/go/auth"
)
type Firebase struct {
Auth *auth.Client
}
func NewFirebase() (inst *Firebase, err error) {
inst = new(Firebase)
// GOOGLE_APPLICATION_CREDENTIALSで指定した認証情報ファイルを暗黙的に読み込む
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
return
}
authInst, err := app.Auth(context.Background())
if err != nil {
return
}
inst.Auth = authInst
return
}
認証処理
これは後から説明するgrpc_auth.UnaryServerInterceptor
で引数に使用する認証メソッドを持つレシーバの定義です。先ほどのFirebaseをフィールドに持ちます。
package middleware
import (
"context"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
)
type Authentication struct {
firebase Firebase
}
func NewAuthentication(firebase Firebase) *Authentication {
authInst := new(Authentication)
authInst.firebase = firebase
return authInst
}
func (au *Authentication) Authenticate(ctx context.Context) (newCtx context.Context, err error) {
idToken, err := grpc_auth.AuthFromMD(ctx, "bearer")
// JWT の検証
token, err := au.firebase.Auth.VerifyIDToken(context.Background(), idToken)
if err != nil {
return
}
// 引数のコンテキストにtokenというキーにJWTの情報を入れて返す
newCtx = context.WithValue(ctx, "token", token.Claims)
return
}
ちなみに、こちらの記事がわかりやすかったので参考として共有しておきます。Interceptorに関しての説明を読んでおくとこの後の処理の内容がスムーズにわかると思います。
gRPC-GoのMiddleware (Inerceptor) で認証/認可してみる
認証で使用するミドルウェアはGo gRPC Middlewareに定義してあるgrpc_authを使用します。
main.go
package main
import (
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"log"
pb "my-project/grpc"
"my-project/middleware"
"net"
)
func main() {
listenPort, err := net.Listen("tcp", ":800")
if err != nil {
log.Fatalln(err)
}
// Firebaseインスタンスを生成
firebase, err := NewFirebase()
if err != nil {
log.Fatalln(err)
}
// Authenticationインスタンスを生成
auth = *NewAuthentication(*firebase)
// serverに認証設定を追加
server := grpc.NewServer(
grpc_middleware.WithUnaryServerChain(
grpc_auth.UnaryServerInterceptor(auth),
),
// Streamingを使用する場合は必要
grpc_middleware.WithStreamServerChain(
grpc_auth.StreamServerInterceptor(auth),
))
pb.MyProjectServer(server, &handler)
reflection.Register(server)
if err := server.Serve(listenPort); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
まとめ
簡単なgRPCとFirebase Authenticationを使用したGoサーバでの認証処理のやり方でした。認可についても似たようにInterceptorで実装できるので、また別の記事で描こうと思います。
Discussion