使用一次谷歌登录,实现移动应用、自有服务器、谷歌服务和Firebase的集成流程

我是eaglesakura。

使用Firebase Auth,您可以轻松地在应用程序(Android/iOS)和Firebase上进行身份验证。

ですが、単純にFirebase Authだけを使うと、自社サーバー(Appengine含む)からユーザー権限でAPIを呼び出せず(例えばユーザーのGoogle Driveにアクセスする、等)、サーバーとアプリ両方の認証が必要になるなどユーザーとしては認証が複数回発生して煩雑になります。

自社サーバーとGoogle APIとFirebaseを連携させ、なおかつユーザーフレンドリーさを保つために「一度のログインで全リソースへのアクセスを行なう」ために必要な処理をざっくりとまとめました。

SDKが整備されている環境・言語(node.jsとかJavaとか)であれば苦労なく行えますが、整備されていない場合や一部だけ実装する必要がある場合等は参考になるかと思います。

アプリからFirebaseへログイン

Firebase Authの制限

アプリからのログインは基本的に、 Firebase Authentication を利用することで簡単に行なえます。

ただし、これはアプリ <–> Firebase間の連携だけを前提とした場合です。ログインされたユーザーにはFirebaseが自動的にUnique IDを割り振ります。また、対応しているのはFirebaseがサポートしているプロバイダ(Google, Facebook, Twitter等)だけです。

そのため、LINE等の別サービスを組み合わせる場合、もしくは別なサービスのID/PASSでログインさせる場合等はこの方法を使えません。

Custom Tokenによる認証

因此,我们决定将Firebase与我们自己的服务器进行协作。
支持自定义认证系统后,还可以进行以下类似的处理。

    • ログインの可否を自社サーバーでハンドリングできる

 

    • 任意のユーザーIDを割り振れる(ただし文字数制限あり)

 

    • 認証にカスタム情報を付与できる

例えば、 is_eaglesakura:true のようにカスタマイズした情報を付与でき、それを Firebase Rulesからも参照できる

使用JWT进行令牌的发行者验证。

这篇文章中关键的流程是JWT(Json Web Token)。

JWT自体の詳細についてはggると大量にでてきます。JWTは非常に長い文字列で、大まかに覚えておきたいのは次の特性です

    1. ヘッダ・ユーザー情報・署名を持つ

 

    1. 有効期限がある

 

    1. 暗号化はされていないので誰でも内容を見ることができる

 

    1. 署名をされているので、改ざんを検出できる

 

    URL-SAFEであるため、扱いやすい

JWTはそれ自体に署名がついているため、「誰が生成したトークンであるか」を証明することができます。また、有効期限と署名解析時間の問題から、発行 ~ 有効期限切れまでの間に鍵が解析される恐れは(現代のマシンスペックでは)まずないでしょう。

Firebase Custom TokenはJWTを利用して「事前に登録してあるサーバーが発行したトークンである」ことを確認し、ログイン制御(必要に応じてユーザー作成)を行います。

    1. 自社サーバーは、非公開の秘密鍵を持つ

 

    1. 自社サーバーは、JWTに秘密鍵で署名する

 

    JWTを受け取ったFirebaseは、署名をチェックしてJWTが正規ルートで作成されたトークンであることを確認する

创建Firebase服务帐户

Custom Tokenを使ったログインを行なうためには、Firebaseのサービスアカウントを作成する必要があります。

Firebase Consoleからプロジェクトを開き、Overview > プロジェクトの設定 > サービスアカウント > Firebase Admin SDKからサービスアカウントを作成し、秘密鍵(JSONファイル)をダウンロードします。

由于每次下载时,该私钥信息都会更改,因此如果丢失了,只能毫不犹豫地重新发行。

firebase-consoke2.png

以下是记录在JSON中的信息。

    {
      "type": "service_account",
      "project_id": "プロジェクト名",
      "private_key_id": "fa9a899ee2909bd96321a200b124dbb6639ea63d",
      "private_key": "長ったらしい秘密鍵の文字列",
      "client_email": "firebase-adminsdk@example-project.iam.gserviceaccount.com",
      "client_id": "123456789012345678901",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://accounts.google.com/o/oauth2/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk%40example-project.iam.gserviceaccount.com"
    }

生成带有签名的JWT

JWTは広く使われているので、様々な言語でライブラリが存在しています。 jwt.ioのサイトにアクセスすると、JWTのデコードや各言語のライブラリへの誘導をしてくれるので、覚えておくと開発・検証が楽になります。

如果使用Golang的话,似乎广泛使用github.com/dgrijalva/jwt-go。


type TokenSource struct {
    jwt.StandardClaims
    Uid    string`json:"uid,omitempty"`
    Claims map[string]interface{}`json:"claims,omitempty"`
}
source := TokenSource{
    StandardClaims:jwt.StandardClaims{
        ExpiresAt: time.Now().Unix() + 3600,
        IssuedAt:time.Now().Unix(),
        Audience:"https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
        Issuer:"サービスアカウントのメールアドレス",
        Subject:"サービスアカウントのメールアドレス",
    },
    Uid:"FirebaseのユーザーID、任意で指定可能",
    Claims:map[string]interface{},
}

// ユーザーに任意の情報を持たせるときはこうする
source.Claims["is_eaglesakura"] = true

// 秘密鍵のロード
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte("秘密鍵の文字列"));

// JWTの生成
jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, source)

// 署名したJWTの文字列を生成
signed, err := jwtToken.SignedString(privateKey)

生成すると、次のような文字列が生成されます。”.”で区切られた3つのブロックで、jwt.ioで表示させると中身が丸見えであることが確認できます。ただし、署名を付与しているためよほどの計算資源を投入しなければ改ざんはできません。

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQi ...中略... bWFpbCJ9.fSTqP1G1N ...中略... 2388cIWwR1vjqSLF7q8RNrkv1w
jwt.png

在Android上的登录

正しいJWTを生成できれば、アプリからのログインは簡単です。
ドキュメントに従い、Firebase SDKに対してトークンを渡せばログインは完了します。

FirebaseAuth.getInstance().signInWithCustomToken(token)

ログインが正常完了すると、ユーザーIDがサーバーに登録されます。このとき、Firebase Authの標準プロバイダーとは違い、メールアドレスを登録することはできません(それっぽい幾つかのClaimを試しましたが、どれも認識してくれませんでした)

Custom Token Login

与Google账户进行登录和连接

FirebaseのユーザーUIDハンドリングを自社サーバーで行えるようになりましたが、逆に言えばログイン情報の正当性を自社サーバーが保証しなければなりません。

例えば自社で発行したID/PASSを使っている場合はDBに問い合わせる等の処理が必要になりますが、それは負荷の大きな処理です(自社でID/PASSを管理するコストは非常に高い)。

そこで、ユーザーのチェックをGoogleサーバーに行わせることにします。Android/iOS共に、GoogleアカウントによるログインはSDKが提供されているため簡単に実装できます。また、SDKを経由してGoogle標準のログイン画面を出したほうが、ユーザーの信頼という意味で適切です。

比如,用户在WebView中无法确认应用程序显示的登录界面是否为恶意钓鱼网站(因为无法看到URL)。

Googleログインについても、Firebaseのコンソールを利用すると簡単に事前設定を行ってくれます。Overview > プロジェクトの設定 > 全般 > アプリ から、アプリのpackage名とkeystoreのSHA1(Androidの場合)を登録します。SHA1フィンガープリントはオプション扱いですが、未登録の場合はGoogleログインに失敗するので注意してください。

register.png

请参考 google-services-plugin 文档,在下载 google-services.json 文件后进行应用程序注册的实施。

在实施后,传递给登录时的GoogleApiClient.Builder的最基本设置如下。

    public static GoogleApiClient.Builder newFullPermissionClient(Context context) {
        GoogleSignInOptions options = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(context.getString(R.string.default_web_client_id))
                .requestEmail()
                .build();
        return new GoogleApiClient.Builder(context)
                .addApi(Auth.GOOGLE_SIGN_IN_API, options)
                ;
    }

登陆后,将会从谷歌获得一个令牌。

    @OnActivityResult(REQUEST_GOOGLE_AUTH)
    void resultGoogleAuth(int result, Intent data) {
        GoogleSignInResult signInResult = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        if (signInResult.isSuccess()) {
            GoogleSignInAccount signInAccount = signInResult.getSignInAccount();
            // Googleが発行したJWTを得る
            String idToken = signInAccount.getIdToken();
        } else {
            // ログイン失敗...
        }
    }

在Firebase Auth的标准实现中,可以直接将获得的idToken传递给Firebase SDK,但是如果使用自定义令牌,则需要先将其发送到我们自家的服务器,并在此服务器上执行登录处理(例如,在第一次登录时进行用户创建等操作)。

ちなみに、Googleが返却される値の中にある idToken id_token はJWTのフォーマットに従っているため、簡単にデコードが行なえます。

在服务器上验证Google的IdToken

アプリからサーバーに送られてきたJWTが正しいものかどうか、自前で検証しなければなりません。幾つかの言語ではSDKが用意されていますが、それ以外の環境・言語でもGoogleが公開しているAPIによって検証を行えます。

// https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={IdToken}
// 上記APIで200が返ってくれば、Googleが発行したJWTであることが保証される
resp, err := urlfetch.Client(ctx).Get("https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=" + googleLoginToken)

// respを検証する...

200である場合、返却されるJSONは次のようなフォーマットになります。
IdToken(JWT)が改ざんされている場合や期限切れの場合、エラーが返却されます。

{
 "iss": "https://accounts.google.com",
 "iat": "1487646761",
 "exp": "1487650361",
 "aud": "hogehoge.apps.googleusercontent.com",
 "sub": "108644137959533113614",
 "email_verified": "true",
 "azp": "fugafuga.apps.googleusercontent.com",
 "email": "example@gmail.com",
 "name": "Takeshi Yamashita",
 "picture": "https://lh5.googleusercontent.com/path/to/picture/photo.jpg",
 "given_name": "Takeshi",
 "family_name": "Yamashita",
 "locale": "ja",
 "alg": "RS256",
 "kid": "926d60cd055911f75f324adde1708d932f9595af"
}

email name の値を見れば、ユーザーのメールアドレス等が得られるため、ユーザーの初期情報として十分かと思われます。

ただし、この値は素通りさせてはいけません。絶対に aud の値を検証するようにしてください。これは「誰に対して発行されたトークンであるか」を示します。ここで見覚えのないIDを素通りさせてしまうと、攻撃者が作った適当なトークンでログインされてしまう恐れがあります。

    1. 攻撃者が適当なGCPプロジェクトを用意しする

 

    1. 攻撃者が[1]で作った適当なアプリからログインし、正規ルートでGoogleのIdTokenを手に入れる

 

    1. 攻撃者が[2]で得たIdTokenを使ってログインを行なう

aud のチェックをしない場合、[3]でログインが行えてしまう

Googleが用意しているSDKを経由すれば内部で aud の検証を行ってくれますが、自力で検証する場合は忘れずに行なうようにしましょう。

ユーザーの妥当性がチェックできたら、前述のCustom Token用JWTを発行してアプリに返却し、アプリ側でCustom Tokenによるログインを行わせれば完了です。

在本公司的服务器上使用Firebase认证凭证

通过这个,Firebase的认证和用户管理现在可以完全由我们自己的服务器处理。

次に問題となるのは、ログイン後の継続した自社サーバーとアプリとの通信認証です。
多くの場合、ログイン後、自社サーバーが発行したトークンをアプリ内に保存し、通信時にHttpのヘッダに乗せることで認証を行なうことが多いかと思います。

AndroidやiOSでは基本的に一度アプリでログインしたあとはずっとログインしっぱなしであるため、何度もログインさせることは(セキュリティ上の必要な場合を除けば)望ましくありません。そのため、ログイン済の通信トークンを端末のどこかに置いておく必要があります。

JWTはトークン改ざんを検出できるためかなり安全な通信トークンとなりますが、一般的には有効期限が短い(1時間)ため、定期的な再発行が必要になります。ですが、再発行のために必要なGoogleログイン情報も1時間で有効期限が切れるため、再利用ができません。

GoogleのOAuthのようにrefresh_tokenを用いて定期的にトークンを交換させる場合はわざわざAPIを設ける必要があり、コストが高くなります。また、永続利用可能な通信トークンをサーバーから発行した場合でも、アプリ側で「安全にトークンを保存する」というコードを記述しなければなりません。

手軽にこれらの問題を解決するため、Firebase Authのトークン管理の仕組みを拝借してみましょう。Firebase SDKは内部でトークンのリフレッシュを行ってくれるため、Firebaseの通信トークンをそのまま自社サーバーの通信トークンとして流用することができます。

また、アプリ内でのトークン管理もFirebase SDKに任せることができます。

Firebaseの通信トークンを得る

Androidの場合、トークンの取得は簡単です。
取得したトークンはJWTのフォーマットで、なおかつ有効期限が1時間です。この情報をhttpの Authorization ヘッダに乗せるなど、適当な手段でAPIのパラメータと一緒に送ります。

由於這個令牌是一個很長的字符串,如果無法放在標頭中,可能需要考慮使用查詢字符串或其他合適的代替方法。

// Tokenを取得する
// 実際には非同期処理なので、取得待ちを行なう必要がある
FirebaseAuthorizeManager.getInstance().getToken(true);

从 Firebase SDK 的 getToken() 方法获取的 JWT 如下所示。

custom token.png

在服务器上进行Firebase令牌验证。

サーバーに送られてきたトークンは、「Googleが、自分のFirebaseプロジェクトのために署名したデータである」ということを確認しなければなりません。

自分のFirebaseプロジェクトのために署名した ことは、JWTの aud や iss をチェックすることで確認できます。次に、そもそも送られてきたトークンがGoogleが署名したデータであることを検証しなければなりません。

そのときに使用するのが、ヘッダ部に付与されている kid の値と、Googleの公開鍵サーバーです。FirebaseのTokenは、Googleが持つ秘密鍵で署名されるため、Googleの公開鍵サーバーから公開鍵を取得すれば署名が正しいことをチェックできます。

公開鍵の取得は、次のURLで行えます。

    • https://www.googleapis.com/robot/v1/metadata/x509/{サービスアカウントのメールアドレス}

 

    • Googleが署名するデータを検証する場合は次のアドレスで固定

https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com

{
 "06cc632ebf3d40d879839fe44af4cdddf6b56c57": "-----BEGIN CERTIFICATE----- ...中略 ...-----END CERTIFICATE-----\n",
 "3d7f476544bf10f0024de011f19b6973c210c7ff": "-----BEGIN CERTIFICATE----- ...中略 ...-----END CERTIFICATE-----\n",
 "1328564e372a3c5829cfc11895453e157f88dd48": "-----BEGIN CERTIFICATE----- ...中略 ...-----END CERTIFICATE-----\n",
 "dd624715cdffb176a7c5d80d3e748282a811f7fb": "-----BEGIN CERTIFICATE----- ...中略 ...-----END CERTIFICATE-----\n"
}

先程のスクリーンショットの例だと、 06cc632ebf3d40d879839fe44af4cdddf6b56c57 というkidで署名されているので、 06cc632ebf3d40d879839fe44af4cdddf6b56c57 とペアになっている公開鍵で検証を行えます。

最初にCustom Tokenを作成したときの署名情報も、このAPIを使って公開鍵を得ることができます(自分のサービスアカウントのURLを試してみてください)。

注意点として、Googleの公開鍵は定期的に追加・削除されてしまいます(JWT自体が1時間しか有効期限が無いため、基本的に困りません)。ですので、Unit Test等で「この鍵が存在しているはず」とか、「アプリにGoogle公開鍵一覧を内蔵する」ような実装は避けて、正しく鍵を得るようにしましょう。

谷歌的公钥寿命很短,所以我们可以在内存中缓存,并在有陌生kid请求时重新加载,这应该不会有问题。

对于jwt-go,验证签名的步骤如下。

rawToken, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
    kid := token.Header["kid"].(string)
    return jwt.ParseRSAPublicKeyFromPEM([]byte("kidに対応した公開鍵の文字列"))
})

// Verifyに失敗してもrawTokenは返却されるので、errorをチェックする
if strings.Contains(err.Error(), "crypto/rsa") {
    // Verify error
    return nil, newTokenError(err)
}

// TODO: audをチェックする

// 問題ない鍵ならば、`user_id`の値からユーザーとして扱う

现在,通信令牌的问题也解决了。
我认为与我们公司服务器的通信并不需要太过担心,我们可以通过一些力量来解决,所以请把这只作为一个例子。

自社サーバーからFirebaseのリソースにアクセスする

Firebase SDKが用意されているプラットフォームであれば、自由にリソースアクセスできるので、それを使いましょう。
もしSDKが用意されていない場合、REST APIを使ってアクセスすることができます。

Firebase Databaseへサービスアカウント権限でアクセスする

自社サービスでFirebaseと連携する場合で、かつSDKが用意されていない言語やプラットフォームであれば、APIを直接利用してデータベースやストレージへアクセスしなければなりません。

GoogleのAPI全体のルールとして、認証はJWTのトークンではなく、OAuth2のトークンを利用する必要があります。
ですので、自社サーバーからFirebaseへアクセスするためには、先程作ったJWTトークンをサービスアカウント用のOAuth2トークンに交換しなければなりません。

サービスアカウントでトークンを取得するのは非常に簡単で、Googleが規定するデータをJWTのフォーマットでPOSTしてあげます。

Scopeは使いたい機能によって様々ですが、Firebase Databaseにアクセスしたい場合は https://www.googleapis.com/auth/firebase https://www.googleapis.com/auth/userinfo.email の2つが必須です。
複数個のスコープが必要な場合は、半角スペースで区切ります。


type TokenSource struct {
    jwt.StandardClaims
    Scope  string`json:"scope,omitempty"`
    Claims map[string]string`json:"claims,omitempty"`
}

source:TokenSource{
    StandardClaims:jwt.StandardClaims{
        ExpiresAt: time.Now().Unix() + 3600,
        IssuedAt:time.Now().Unix(),
        Audience:"https://www.googleapis.com/oauth2/v4/token",
        Issuer:"サービスアカウントのメールアドレス",
        Subject:"サービスアカウントのメールアドレス",
    },
    Scope:"https://www.googleapis.com/auth/firebase https://www.googleapis.com/auth/userinfo.email",
    Claims:map[string]string{},
}

// jwtで変換してサービスアカウントの鍵で署名する...

// 署名後のjwtをPOSTする
values := url.Values{}
values.Add("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
values.Add("assertion", 署名済jwt文字列)
resp, err := urlfetch.Client(it.context).PostForm("https://www.googleapis.com/oauth2/v4/token", values)

// 200であれば、access_tokenが手に入る

得られたTokenは、Authorization ヘッダに Bearer ${access_token} として与えれば、Firebase Databaseにアクセスすることができます。このトークンはService Accountなので、DatabaseのRulesを無視したあらゆるリソースにアクセス・書き換えを行えます。

このトークンの有効期限も1時間です。すぐに使えなくなるため、オンメモリキャッシュに保存したり、Memcache等の安価な一時領域に置いておくと良いかと思います。

curl -H "Authorization: Bearer {access_token}" https://{プロジェクト名}.firebaseio.com/.json

使用服务帐号权限访问Firebase存储。

Firebase StorageはGoogle Cloud Storageと統合されています。
サービスアカウント側からはGCSのAPIでアクセスし、アプリ側からはFirebase SDKを経由したアクセスをすると管理が楽になるかと思います。

自社サーバーからアクセスする場合、スコープに https://www.googleapis.com/auth/cloud-platform を加えます。また、GCSのAPIで指定するバケット名は {プロジェクト名}.appspot.com で固定となります。

请查阅官方文档以获取API清单。

如果想要获取存储在Firebase Storage中的文件列表,可以按照以下方式使用。

curl -H "Authorization: Bearer {access_token}"  https://www.googleapis.com/
storage/v1/b/{firebaseプロジェクト名}.appspot.com/o

从我们自己的服务器访问用户的Google账户资源。

自社サーバーで定期的な処理を行いたい場合(例えばユーザーのGoogle Driveにバックアップする等)は、自社サーバーからユーザーリソースへのアクセス手段を確保しなければなりません。

前述のように、GoogleのAPIアクセスはOAuth2のaccess_tokenに統一されています。サーバーのJWTやユーザーがGoogleから受け取ったJWTからOAuth2のaccess_tokenを生成できれば楽ですが、残念ながら直接的な手段が提供されていないので、少し遠回りして作成する必要があります。

Google登录的SDK提供了一个选项,可以创建用于服务器端的授权代码,通过使用它,可以获取OAuth2令牌。

在应用程序中添加处理

Firebaseからアプリ情報を作成すると、一緒に WebClient という情報がGCPの認証情報に登録されます。
自動的に生成されるこのクライアントIDとクライアントシークレットをそれぞれアプリに追記します。

ありがたいことに、サーバー側にOAuthのコールバック用ハンドラを記述する必要はなく、SDKが全て行ってくれます。

google web client2.png
web-client.png
    // builderにrequestServerAuthCodeを追加する
    public static GoogleApiClient.Builder newFullPermissionClient(Context context) {
        GoogleSignInOptions options = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(context.getString(R.string.default_web_client_id))
                .requestEmail()
                 // ↓この行を追加する
                .requestServerAuthCode("クライアントID.apps.googleusercontent.com", true)
                 // ↓サーバー側で欲しい権限があったら、ここで追加しておく
                .requestScopes(new Scope("https://www.googleapis.com/auth/firebase"))
                .build();
        return new GoogleApiClient.Builder(context)
                .addApi(Auth.GOOGLE_SIGN_IN_API, options)
                ;
    }

当执行requestServerAuthCode操作时,在Google登录页面上会增加一个项目,并询问您是否允许离线访问。如果选择是,在这里您可以获得用于在服务器上发行OAuth令牌的授权代码。

add-auth.png
// サーバーに送信する認証コード
String authCode = signInAccount.getServerAuthCode();

在服务器上获取用于用户访问的OAuth2令牌。

在将AuthCode发送到服务器时,必须按照与服务帐号相同的OAuth2令牌转换步骤进行转换。然而,这个AuthCode只能使用一次有效。

在首次获取令牌后,需要使用 refresh_token 每小时进行交换。此外,如果用户明确撤销了访问权限或其他原因,刷新令牌和访问令牌可能都无法使用。

在这种情况下,应该正确处理作为认证错误的情况。如果处理不当,可能会出现一直重新尝试等故障。

// 初回のトークンを取得する
values := url.Values{}
values.Add("client_id", "クライアントID")
values.Add("client_secret", "クライアントシークレット")
values.Add("grant_type", "authorization_code")
values.Add("code", "端末から送られてきた認証コード")

resp, err := urlfetch.Client(it.context).PostForm("https://www.googleapis.com/oauth2/v4/token", values)
// 200なら、"access_token"と"refresh_token"を確保する
// トークンが期限切れした場合にリフレッシュトークンを使ってトークンを再発行する
values := url.Values{}
values.Add("client_id", "クライアントID")
values.Add("client_secret", "クライアントシークレット")
values.Add("grant_type", "refresh_token")
values.Add("refresh_token", "事前に得ていたリフレッシュトークン")
resp, err := urlfetch.Client(it.context).PostForm("https://www.googleapis.com/oauth2/v4/token", values)

可以通过调用谷歌的用户信息API来获取用户信息,而无需发送IdToken,以从获得的OAuth2访问令牌中获取。

curl -H "Authorization: Bearer {access_token}" https://www.googleapis.com/oauth2/v1/userinfo?alt=json

现在只需要一个登录页面,就可以完成“Google账户的认证”、“Firebase的登录和访问控制”以及“从服务器访问用户的Google账户”这三项功能。

最终认证/处理程序

提前准备

GCPのプロジェクトを作成する

FirebaseプロジェクトとGCPプロジェクトをリンクする

Firebaseにサービスアカウントを登録する

Firebaseのサービスアカウントの秘密鍵を取得する

FirebaseにAndroid/iOS等のアプリ情報を登録する

必要なGoogle APIを有効化する

登录步骤

    1. [设备] 在Google登录选项中添加所需的服务器访问范围

 

    1. [设备] 在选项中添加Web Client的客户端ID

 

    1. [设备] 将通过Google登录获得的IdToken和服务器访问代码发送到服务器

 

    1. [服务器] 检查接收到的信息的有效性,进行OAuth认证信息获取以及保存刷新令牌等操作

 

    1. [服务器] 生成JWT并返回给设备

 

    1. [设备] 使用返回的JWT执行基于自定义令牌的登录

 

    [设备] 如果Firebase登录成功,则登录完成。

登录后的通信步骤

    1. [端末] 通信前にFirebaseログイン情報の通信トークンを取得する

 

    1. [端末] Firebaseのトークンをhttpのヘッダ等に乗せて自社サーバーのAPIを呼び出す

 

    1. [サーバー] Firebaseのトークンが正しく署名されているか検証する

 

    [サーバー] 署名が正しいなら、user_id のユーザーとしてサーバーの処理を行なう

服务器访问Firebase资源

    1. [服务器] 生成JWT并获取服务帐号的OAuth2令牌

 

    [服务器] 在Authorization头中携带OAuth2令牌调用REST API

服务器访问用户的Google资源。

    1. [服务器] 从终端接收访问代码并获取refresh_token。

 

    1. [服务器] 如果access_token已失效(例如到期),使用refresh_token重新获取访问令牌。

 

    [服务器] 将OAuth2令牌放入Authorization标题中,以调用REST API。

エンドポイント一覧

由于我自己也经常忘记,所以我将终点和有用的网站列表记在这里。

    • Google API Console

https://console.developers.google.com

Firebase Console

https://console.firebase.google.com
先にGCPのプロジェクトを作成してからリンクさせるほうが良い

JWTの検証を行なう

https://jwt.io

GoogleのID Tokenを検証する

https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=

サービスアカウントの公開鍵を得る

https://www.googleapis.com/robot/v1/metadata/x509/{アカウント}
Googleはコレで固定

https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com

OAuth2アクセストークンを得る

https://www.googleapis.com/oauth2/v4/token

OAuth2アクセストークンの検証を行なう

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={アクセストークン}

bannerAds