Firebase Authenticateに触れてみる①

イントロ

ちょっとした思いつきで、pet projectとして小さなサービス作ってみるか!!というのを昨日の夜に思いついたのですが。
・・年末〜年始でやろう!と思って熱の引いてたネタの焼き直しで。ふと「これなら形にできそうだぞ!」というアイディアが浮かんだので。

で、テーブル設計とかばっと出しつつ、必要な画面を考え始めたところで「ユーザー登録/認証周りどうしようかな〜」っていう・・・
作るだけなら強制ログイン状態を生み出して、まず「動くように作る」をして、そっから考えよ〜!でも良いのだし。そうするつもりだったのですが。

うん、パスワードとかtokenとか預かるの嫌だ!
やるにせよ、何か今風のないのかな〜と。

GitHub/Twitter/Gmail辺りのOAuth連携をやるか、昔ながらのId/Passログインを作るか。ああ、tokenも預かりたくないし、かといって改竄できそうなのも嫌だし、パスワードも預かりたくねぇな〜ていうかソーシャルのアバター使いてぇな〜なんかな〜〜〜

ってことで、Firebase Authenticateを使ってみようと思いたち。

すごい雑なログインシステム(まで

びっくりするくらい簡単に動いてしまって、まだびっくりしてます。

  1. まず プロジェクトを作る https://console.firebase.google.com/
  2. Authentication -> sign-in method で(とりあえず) email/passを有効にする f:id:o0h:20190105170721p:plain
  3. コンソールのPJ概要にあるスニペットとウェブサイトで Firebase Authentication を使ってみる  |  Firebase を参考にいじる f:id:o0h:20190105171203p:plain

で、出来上がったのが下のようなもの。

すごく雑なFirebaseAuthenticateログインフォーム · GitHub

・・・これだけでちゃんと動くっていう。。 驚きがありませんか。

やりたいことを整理する

モチベーションは「ログイン・認証機構をこっちで作りたくないし、秘密情報をこっちのストレージにおいておきたくない」です。
こんな我儘を実現するシステムとは・・・

  1. エンドユーザーの操作によって、3rd partyのプロバイダに対して、「有効なアカウント」のお墨付きをもらってくる
  2. エンドユーザーから、こちらのサーバーに「安全で安心な認証済み情報」が送られてくる
  3. こちらのサーバー上にあるユーザーデータと紐付けて、ログイン処理を実行する

このあたり、なんとなくJWTとか使ってみたら行けるのかな〜どうかな〜って思ってるんですけどね。使ったことないので。試してみる。

ココらへんを読み解けば良いかな?

fireabase的には firebase.auth().currentUser.getIdToken()で「トークン」がとれる、と。
この値をhttps://jwt.io/ でデバッガに渡してみると、認証情報が入ってるっぽい。

f:id:o0h:20190105174459p:plain

このuidの値から、こちらのユーザーデータに対して同一性を手繰り寄せて行けばよいのかな?
やってることはコレっぽいな。
Firebase Auth のユーザ認証機能を自前のデータベースと連携する - Qiita 「Firebase Admin SDKを使うか、JWTライブラリを使うか」という、正にドキュメント上で言及されていた分岐があるだけ〜という感じがする。

どっちも内容は同じな気がしていて、「Firebase Admin SDKを利用するメリットはなにか」というと、ドキュメントに書かれているこの辺りか。

提供された ID トークンが正しい形式で、期限切れではなく、適切に署名されていれば(デコードされた情報を取得できます)

逆にJWTについての但し書きは

(利用するためには)ID トークンのヘッダー、ペイロード、署名を確認します。

となっている。

つまり、JWT実装した場合は自前で検証をしなければならないーと。

先に貼った「CakeでJWT認証やってみよう」の記事においては 10. Testing JWT Authentication の部分に当たるかな?

ということで、やることとしては

  1. client側では、Firebase Authenticateを通ったあとに「トークン」をこっちのサーバーに投げる
  2. こっちのサーバーでは、投げられたトークンを検証する
  3. 検証に通ったらアプリケーション上でのユーザー同定・ログイン処理を行う

ができりゃ、いーかなぁ

実際に「外部プロバイダ」でログインやってみる with GitHub

大体の処理の流れは掴んだ?と思うので。あとは理屈で覚えるより動かしながら眺めてみる。

ってことで、GitHubログインをやってみたい

JavaScript を使用して GitHub で認証する  |  Firebase

  • まずは sign-in method でGitHubを有効にして f:id:o0h:20190105175810p:plain
  • callback urlを確認して
  • GitHubの認証appを新規作成して https://github.com/settings/applications/new
  • さっき確認したcallback urlを参考にしつつ必要な情報を埋めて
  • 登録するとアプリケーション詳細ページに飛ぶのでClient ID/secretを確認して
  • Firebase consoleに戻って、ID/secretを記入する

サービス側の設定はこれでOK。
ココらへんから「HTMLファイルを直開き」だと動かなくなってくる(http:// or https:// で始める必要がある)ので、必要に応じて firebase serveコマンドなどを用いてローカルサーバーを利用する

先のドキュメントを参考にして、スクリプトを書いていく ・・・いちおうgistにも貼ってはいるけれど、これだけで動いちゃう・・・

const provider = new firebase.auth.GithubAuthProvider();
firebase.auth().signInWithPopup(provider).then((result) => {
  console.log(result.user)
}).catch((error) => {
  alert(error.message)
})

f:id:o0h:20190105184503g:plain

意味わからないですね簡単すぎて・・・・

ということで、あとはサーバーサイドの実装。

簡単なusersテーブル付きのログインできるcake appを書く

もう、べったり先のブログを参考にして。 プラグイン使ってJWT認証どのくらい簡単にできるかな?に挑みます。

github.com

あ、でもCRUDプラグインはいいや。

ココらへん使いつつ、Docker環境用意してcakephp/appのproject作って〜っていうのはいつもの通りなので省略。

1. cakephp-jwt-authプラグインの設置

このように

# composer require admad/cakephp-jwt-auth
Using version ^2.3 for admad/cakephp-jwt-auth
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Installing firebase/php-jwt (v5.0.0): Downloading (100%)
  - Installing admad/cakephp-jwt-auth (2.3.2): Downloading (100%)
Writing lock file
Generating autoload files
> Cake\Composer\Installer\PluginInstaller::postAutoloadDump
/app # bin/cake plugin load ADmad/JwtAuth

/app/src/Application.php modified

2. usersテーブルの設置

親切にMigrationファイルのサンプルとか用意してくれてるの。すげー

users.php

で、ちょっと内容を変えたいので(icon urlとか足してみたい)、参考にしつつ少しいじる

  1. bin/cake bake migration CreateUsers して
  2. こんな感じの内容を(下記
  3. bin/cake migrations migrate する
<?php
use Migrations\AbstractMigration;

class CreateUsers extends AbstractMigration
{
    /**
     * Change Method.
     *
     * More information on this method is available here:
     * http://docs.phinx.org/en/latest/migrations.html#the-change-method
     * @return void
     */
    public function change()
    {
        $this->table('users')
            ->addColumn('name', 'string', [
                'default' => null,
                'limit' => 64,
                'null' => false
            ])
            ->addColumn('avatar_url', 'string', [
                'default' => null,
                'limit' => 256,
                'null' => false
            ])
            ->addColumn('created', 'timestamp', [
                'default' => 'CURRENT_TIMESTAMP',
                'limit' => null,
                'null' => false
            ])
            ->addColumn('modified', 'datetime', [
                'default' => null,
                'limit' => null,
                'null' => true
            ])
            ->create();
    }
}

3. users周りのコードをザクッと

bin/cake bake all Users しておく。
いろいろなファイルが出来上がる。

この時点で、 /users/add とかを見ると、画面ができているよね f:id:o0h:20190105202838p:plain

4. サインイン用のAPIエンドポイント

ここからが本番!って感じ。

tokenを投げてユーザー登録をする先 が必要になるので。

/api/user/signup.json とでもしよう。

routes.phpに下記を追記

<?php
Router::scope('/', function (RouteBuilder $routes) {
    // 省略
    $routes->prefix('api', function (RouteBuilder $routes) {
        $routes->setExtensions(['json']);
        $routes->post('/users/signup', ['controller' => 'Users', 'action' => 'add', 'prefix' => 'api']);
    });

src/Controller/Api ディレクトリを新設し、以下のように UsersController を作成

<?php

namespace App\Controller\Api;

use App\Controller\AppController;
use Cake\Http\Exception\NotImplementedException;

class UsersController extends AppController
{

    public function add()
    {
        throw new NotImplementedException('これからね!');
        
    }
}

この時点で、一旦routes.phpから $routes->applyMiddleware('csrf'); をコメントアウトしておいて、こんな感じのcurlを打ってみる

curl -X "POST" "http://localhost:8101/api/users/signup.json" -H 'Content-Type: application/json; charset=utf-8'

これで status:ok といったレスポンスが返ってくれば、routingはこれでOK!

5. Enabling JWT Authentication

とのことなのだけど・・・はて・・・

長くなってきそうなので、一旦ここまで!

次にやることは

  1. cakephp-jwt-auth の仕事や中身について理解する
  2. 「How to add JWT Authentication to a CakePHP 3 REST API」で説明されているシナリオについて理解する
  3. 実際にFirebase Authenticateを利用したGItHubログインを実装してみる

で!

daisuki.nichiyoubi.land