はじめに

Rails(devise)のユーザーを Firebase Authentication にエクスポートする方法。

TL;DR

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. 環境設定
    2. インポート用ファイルの作成
    3. インポート
    4. 認証可能か確認
  5. その他・メモ
    1. ID について
  6. まとめ
  7. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Rails 環境
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]

$ rails -v
Rails 5.1.4

$ grep devise Gemfile.lock
devise (4.4.0)

# Firebase CLI 実行環境
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.7
BuildVersion: 19H2

$ firebase -V
8.12.1

詳細

参考:


公式ドキュメント に記載されている通り、Firebase CLI を使うことで Firebase auth へのユーザーインポートが可能。

なので devise で登録されているユーザー情報を、Firebase auth でインポート可能な形式(CSV or JSON)で出力して、firebase auth:import コマンドでインポートすれば OK。

環境設定

firebase CLI が入ってなければセットアップ。自分は Mac なので brew でインストールした。

1
2
3
4
$ brew install firebase
...
$ firebase -V
8.12.1

firebase にログイン、ブラウザが開くのでブラウザ上で操作する。

1
$ firebase login

firebase init で初期化、どの機能を使うか聞かれるので最低限どれか 1つは選択して進めていく。Web conosle でプロジェクト作成済みであれば、プロジェクト選択もできる。

1
2
$ firebase init
...

インポート用ファイルの作成

参考: auth:import と auth:export | Firebase

CSV 形式、JSON 形式でインポートができる。今回は参考ページにならって JSON とした。

元記事では rake タスクを作ったと書かれているが、今回は技術調査が目的だったので rails c で作業した。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# rails c でコンソール接続
open('tmp/users.json', 'w') do |f|
# とりあえず1ユーザーだけ試した。
# 複数ユーザーの場合は、元記事のように find_each などでユーザー数分回す。
user = User.first
data = {users: []}
ju = {
localId: user.id,
email: user.email,
emailVerified: user.confirmed_at.present?,
passwordHash: Base64.encode64(user.encrypted_password).gsub(/\n/, ''),
createdAt: user.created_at.to_i * 1000,
lastSignedInAt: user.last_sign_in_at.to_i * 1000,
# 他フィールドも必要であれば https://firebase.google.com/docs/cli/auth#JSON を参考に追加
}
data[:users] << ju
f.puts data.stringify_keys.to_json
end

tmp/users.json として以下のようなファイルができるはず。(見やすいように改行している)

1
2
3
4
5
6
7
8
9
10
{
"users": [{
"localId": 12345,
"email": "foo@example.com",
"emailVerified": true,
"passwordHash": "JDJh...RkJH",
"createdAt": 1602575053000,
"lastSignedInAt": 1602575860000
}]
}

インポート

以下コマンドでインポートできる、--debug を付けると詳細情報が表示される。上手くいけば ✔ Imported successfully. となるはず。

1
2
3
$ firebase auth:import users.json --debug --hash-algo=BCRYPT --hash-key="xxxx"
...
✔ Imported successfully.

--hash-keyrails c 上で Devise.secret_key で確認できる。

1
2
Devise.secret_key
# => "xxxx"

元記事 では --rounds を指定しているが、ドキュメントを見る限り BCRYPT に関係なさそうなので自分は削除した。

パスワードのハッシュに使用されるラウンド数。
SCRYPT、MD5、SHA512、SHA256、SHA1、PBKDF_SHA1、PBKDF2_SHA256 のアルゴリズムに必要です。

認証可能か確認

参考:


探した限り、簡単に認証テストができるツールやらサンドボックスやらは無いようなので、アプリを追加して検証する。

test.html を作成して、スクリプトを貼り付け。firebase-auth.js を追加で記述する必要があるので注意。

auth().signInWithEmailAndPassword() でログインできるか検証。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Document</title>
</head>
<body>
<script src="https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.23.0/firebase-auth.js"></script><!-- *** 追加 *** -->
<script src="https://www.gstatic.com/firebasejs/7.23.0/firebase-analytics.js"></script>
<script>
var firebaseConfig = {
apiKey: "xxxx",
authDomain: "xxxx",
databaseURL: "xxxx",
projectId: "xxxx",
storageBucket: "xxxx",
messagingSenderId: "xxxx",
appId: "xxxx",
measurementId: "xxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();

const email = 'foo@example.com'; // *****
const password = 'YourPassword'; // *****
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function (res) {
document.body.insertAdjacentHTML('afterBegin', '<h1>signin success</h1>');
})
.catch(function(error) {
document.body.insertAdjacentHTML('afterBegin', '<h1>signin failed</h1>');
});
</script>
</body>
</html>

test.html をブラウザで開いて signin success と表示されれば問題なし。

その他・メモ

ID について

Firebase の uid は alphanumeric(20) らしい(参考: 【Firestore】ドキュメントの自動生成 ID って被らないの? - Qiita)ので、合わせるなら SecureRandom.alphanumeric で生成。

1
2
3
require 'securerandom'  # rails の場合は require 不要
SecureRandom.alphanumeric(20)
# => "atyDwoUizwzDXBmMVNZ1"

ただし、衝突しないとは限らないので既存データを確認する処理も追加する必要があるため注意。

まとめ

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list