Firebaseの認証機能

今回は、Firebaseの認証機能について見ていきます。Firebaseでは表のようにGoogleやFacebook、Twitterなどのサードパーティが提供する方式も含めて7種類ほどの認証方式がありますが、ここでは標準的なメールアドレスとパスワード(Email & Password)を使用する方式を見ていきます。メールアドレスとパスワードによる認証は分かりやすくおススメです。
表:Firebaseがサポートする認証形式
プラットホーム | 記述 |
---|---|
カスタム(Custom) | 独自のログイントークン(login token)を作成。既に使用している認証システムと統合する場合に使用する。サーバ側処理の認証用としても使用できる |
メールアドレスとパスワード(Email & Password) | Firebaseがパスワードを管理し、メールアドレスとパスワードでユーザの登録と認証を行う |
Anonymous(匿名の) | 各ユーザに1セッションが続く間有効なユニークな(一意の)識別子を生成する |
Facebookを使用してクライアント側のコード記述のみでユーザ認証を行う | |
Twitterを使用してクライアント側のコード記述のみでユーザ認証を行う | |
GitHub | GitHubを使用してクライアント側のコード記述のみでユーザ認証を行う |
Googleを使用してクライアント側のコード記述のみでユーザ認証を行う |
メールアドレスとパスワードによるFirebase認証
ここから、メールアドレスとパスワードを使用したFirebase認証の処理手順を説明します。プログラムの作成と配置は第3回で紹介したApp Engineを使用しますので、基本的な使用方法および処理手順についてはそちらを参照してください。なお、GoogleのクラウドにはApp Engine以外に
2種類のプログラムを作成する
メールアドレスとパスワードによる認証では2種類のプログラムを作成します。1つは認証機能を持つユーザアカウントを作成するプログラム、もう1つは認証処理を使用してFirebaseにログインするためのプログラムです。
認証用ユーザアカウントの作成
Firebaseには認証用アカウントの作成と管理用に作成されたJavaScriptメソッドが用意されています。リスト1はユーザアカウント作成用のテンプレートコードです。
リスト1:ユーザアカウント作成のテンプレートコード
01 | var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); //(1) |
02 | ref.createUser({ //(2) |
03 | email : "bobtony@firebase.com", //(3) |
04 | password : "correcthorsebatterystaple" //(4) |
05 | }, function(error, userData) { |
06 | if (error) { |
07 | console.log("Error creating user:", error); |
08 | } else { |
09 | console.log("Successfully created user account with uid:", userData.uid); |
10 | } |
11 | }); |
リスト1では、(1)で生成したFirebaseリファレンス(ref)に(2)のcreateUserメソッドで(3)のメールアドレス(email)と(4)のパスワード(password)を指定し、新規のユーザアカウントを作成しています。
ユーザログイン
続いて、リスト2はユーザログインの処理テンプレートです。アカウントの作成後、ユーザはリスト2のような処理手順でログインします。
リスト2:ユーザログインのテンプレートコード
01 | var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); |
02 | ref.authWithPassword({ //(1) |
03 | email : "bobtony@firebase.com", //(2) |
04 | password : "correcthorsebatterystaple" //(3) |
05 | }, function(error, authData) { |
06 | if (error) { //(4) |
07 | console.log("Login Failed!", error); |
08 | } else { |
09 | console.log("Authenticated successfully with payload:", authData); |
10 | //(5) |
11 | } |
12 | }); |
リスト2では、(1)のauthWithPasswordで(2)のemailと(3)のpasswordによる認証を要求し、(4)の認証に失敗した場合と(5)の成功した場合に分けてそれぞれの処理を行います。
作成したプログラムの画面処理
次に、上記で作成したユーザログインの処理テンプレートを、これまで作成したFirebaseプログラムに組み込んだ場合の処理手順を説明します。最初に画面処理を確認し、その後に実行するプログラムコードを見ていきます。
ユーザの登録
図1は認証処理のメニュー画面です。(1)でユーザ・パスワードの設定を行い、(2)でパスワードによりログインとチャットを実行します。(3)(4)はまだテンプレートコードを紹介していませんが、(1)と(2)の一連の処理を見た後で触れます。
なお、このサンプルでは(1)の認証情報設定と(2)の認証実行、およびその後の処理を同じメニュー画面上に配置していますが、実際の運用ではこの2つを分け、認証情報の設定は別画面で行うのが通常でしょう(図2)。
メールアドレスとパスワードを入力して「実行」をクリックすると、ユーザの認証情報が作成されます(図3)。
図3の画面で作成される認証情報(セキュリティに関する情報)はユーザから見えるデータベースには格納されず、Firebase認証サーバの背後にあるユーザからは見えないセキュアなデータ・ベースに格納されます。データは「BCrypt」(注)方式で暗号化することで機密性が要求されるセキュリティ情報をアプリケーションデータから切り離し、ユーザはアプリケーション作成とユーザインターフェイスに注力できるようになります。
※注:BCryptは「Blowfish」と呼ばれる暗号化方式をプログラムで利用できるように実装したもの。ライセンスフリーであること、他の暗号化方式と比べて比較的高速であることから認証システムでよく利用されている暗号化方式です。
Firebaseチャットの実行
ユーザアカウント作成に成功したら、Firebaseのチャットを実行する画面(図4)に移ります。メールアドレスとパスワードを入力して「ログイン」をクリックします。認証が成功すると、画面下部にこれまでのチャットメッセージが表示されます。次に、認証機能を付加した画面で、これまで同様に複数画面間でのリアルタイム表示を確認してみます(図5)。2つの画面が表示されていますが、それぞれのメールアドレス(ユーザ)は異なっています。
後に表示された画面で認証が成功すると、これまでと同様にチャットメッセージが表示されます(図6)。サンプルでは2つの画面が同じPCディスプレイ上に表示されていますが、ログインユーザは別であり、他のPCでも同様の画面表示になります。
次に、図6の後に表示された画面でチャットメッセージを入力して「書き込み」ボタンををクリックすると(図7)、もう一方の画面にもチャットメッセージが表示されます(図8)。
なお、図8の両方の画面にリアルタイムでメッセージが表示されますが、ポイントはFirebase用のHTMLファイルが配置されているのはFirebaseに用意されているサイト(firebaseapp.com)ではなく、Googleのクラウドに配された(appspot.com)画面ということです。
セキュリティプログラムを作成する
画面処理に続いて、今度はプログラム処理を見ていきます。これまでと同様に、ポイントはチャット処理プログラムに「ユーザアカウントの作成」と「ユーザログイン処理コード」をどのように組み込むかです。
メニュー画面の作成
リスト3はメニュー画面(図1)のHTMLです。これは問題ないでしょう。
リスト3:メニュー画面(index.html)
01 | <!DOCTYPE html> |
02 | <html> |
03 | <head> |
04 | <meta charset="utf-8"/> |
05 | <script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script> |
06 | <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> |
07 | <title>Firebase Simple apli</title> |
08 | </head> |
09 | <body bgcolor="#bfefdf"> |
10 | <h2>Firebase メールアドレスとパスワードでセキュリティ設定</h2> |
11 | <p><a href="email-ui.html">(1) ユーザ・パスワード設定</a></p> |
12 | <p><a href="email-fb.html">(2) パスワードログイン・実行</a></p> |
13 | <p><a href="email-ce.html">(3) メールアドレス変更</a></p> |
14 | <p><a href="email-cp.html">(4) パスワード変更</a></p> |
15 | </body> |
16 | </html> |
ユーザ・パスワード設定画面の作成
リスト4はユーザ・パスワード設定画面(図2)のHTMLです。リスト1との違いは(1)と(2)でメールアドレスとパスワードを画面入力の値に換え、後はステータスを表示しているところだけです。
リスト4:ユーザのメールアドレスとパスワード登録処理(email-ui.html)
01 | <!DOCTYPE html> |
02 | <html> |
03 | <head> |
04 | <meta charset="utf-8"/> |
05 | <script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script> |
06 | <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> |
07 | <title>ユーザ・パスワード設定</title> |
08 | </head> |
09 | <body bgcolor="#bfefdf"> |
10 | <h2>ユーザ・パスワード設定</h2> |
11 | <p>メールアドレス <input type='text' value='sws3gaej4pgm3@gmail.com' id='emailIn' /> |
12 | パスワード <input type='password' value='Minato6Kawaguchi9' id='passIn' /> |
13 | <input type='button' id='passExe' value=' 実行 ' /></p> |
14 | ステータス: <nobr id='stat'></nobr> |
15 | <script> |
16 | $('#passExe').click(function(e){ |
17 | var ref = new Firebase('https://fbase-kseino1.firebaseio.com/'); |
18 | ref.createUser({ |
19 | email : $('#emailIn').val(), //(1) |
20 | password : $('#passIn').val() //(2) |
21 | }, function(error, userData) { |
22 | if (error) { |
23 | $('#stat').text('ユーザ作成エラー'); |
24 | console.log("Error creating user:", error); |
25 | } else { |
26 | $('#stat').text('ユーザ作成成功'); |
27 | console.log("Successfully created user account with uid:", userData.uid); |
28 | } |
29 | }); |
30 | }); |
31 | </script> |
32 | </body> |
33 | </html> |
ユーザ認証とチャット書き込み・表示画面
リスト5は、チャット書き込み・表示画面に認証処理を組み込んでいます。authWithPasswordメソッドでの認証処理では(2)と(3)で画面入力のメールアドレスとパスワードを使用し、成功した場合はチャットメッセージの表示と新規メッセージの入力&コールバック処理を行っています。
リスト5:ユーザ認証とチャット書き込み・表示(email-fb.html)
01 | <!DOCTYPE html> |
02 | <html> |
03 | <head> |
04 | <meta charset="utf-8"/> |
05 | <script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script> |
06 | <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> |
07 | <title>Firebase認証と実行</title> |
08 | </head> |
09 | <body bgcolor="#bfefdf"> |
10 | <h3>ユーザログイン(認証)</h3> |
11 | <p> |
12 | メールアドレス <input type='text' id='emailIn' /> |
13 | パスワード <input type='password' id='passIn' /> |
14 | <input type='button' id='loginb' value=' ログイン ' /> |
15 | </p> |
16 | ステータス: <nobr id='stat'></nobr> |
17 | <hr/> |
18 | <div> |
19 | <h3>チャット表示</h3> |
20 | 名前 <input type='text' id='nameIn' /> |
21 | <nobr id='dtShow'></nobr> |
22 | <input type='button' id='sendMsg' value=' 書込み ' /><br/> |
23 | <textarea id='msgIn' rows='5' cols='70'></textarea> |
24 | </div> |
25 | <script> |
26 | var ref = new Firebase('https://fbase-kseino1.firebaseio.com/'); |
27 | var dtime; |
28 | $('#loginb').click(function(e){ |
29 | ref.authWithPassword({ //(1) |
30 | email : $('#emailIn').val(), //(2) |
31 | password : $('#passIn').val() //(3) |
32 | }, function(error, authData) { |
33 | if (error) { |
34 | $('#stat').text('ログイン不成功'); |
35 | console.log("Login Failed!", error); |
36 | } else { |
37 | $('#stat').text('ログイン成功'); |
38 | if (authData) { |
39 | dateop(); |
40 | $('#sendMsg').click(function(e){ |
41 | var name = $('#nameIn').val(); |
42 | $('#dtShow').text(dtime); |
43 | var text = $('#msgIn').val(); |
44 | ref.push({name: name, dtime: dtime, text: text}); |
45 | $('#msgIn').val(''); |
46 | }); |
47 | ref.on('child_added', function(snapshot){ |
48 | var msg = snapshot.val(); |
49 | dspChatMsg(msg.name, msg.dtime, msg.text); |
50 | }); |
51 | } |
52 | } |
53 | }); |
54 | }); |
55 | function dateop(){ |
56 | var dt = new Date(); |
57 | var year = dt.getFullYear(); |
58 | var month = dt.getMonth()+1; |
59 | var day = dt.getDate(); |
60 | var hour = dt.getHours(); |
61 | var minute = dt.getMinutes(); |
62 | var second = dt.getSeconds(); |
63 | dtime = year+'年 '+month+'月'+day+'日'+hour+'時'+minute+'分'+second+'秒'; |
64 | $('#dtShow').text(dtime); |
65 | } |
66 | function dspChatMsg(name, dtime, text){ |
67 | $('<div/><br/>').text(text).prepend($('<em/>').text(dtime +': ')).prepend($('<em/>').text(name+': ')).appendTo($('#msgDiv')); |
68 | $('#msgDiv')[0].scrollTop = $('#msgDiv')[0].scrollHeight; |
69 | }; |
70 | </script> |
71 | <hr> |
72 | <div id='msgDiv'> |
メールアドレスとパスワードの変更
次に、メールアドレスとパスワードの変更処理について見ていきます。リスト6はメールアドレス変更のテンプレートコードですが、(1)でchangeEmailメソッドを使用していること以外は同じ処理パターンです。
リスト6:メールアドレス変更テンプレート
01 | var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com"); |
02 | ref.changeEmail({ //(1) |
03 | oldEmail : "bobtony@firebase.com", |
04 | newEmail : "bobtony@google.com", |
05 | password : "correcthorsebatterystaple" |
06 | }, function(error) { |
07 | if (error === null) { |
08 | console.log("Email changed successfully"); |
09 | } else { |
10 | console.log("Error changing email:", error); |
11 | } |
12 | }); |
メールアドレスの変更は、図9の画面のように現在(旧)のメールアドレスと新しいメールアドレス、およびパスワードを入力して「実行」ボタンをクリックします。リスト7はメールアドレスの変更処理です。この場合も(1)~(3)の値を画面入力値に変えているだけで、あとは同じです。
リスト7:メールアドレスの変更処理(email-ce.html)
01 | <!DOCTYPE html> |
02 | <html> |
03 | <head> |
04 | <meta charset="utf-8"/> |
05 | <script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script> |
06 | <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> |
07 | <title>メールアドレス変更</title> |
08 | </head> |
09 | <body bgcolor="#bfefdf"> |
10 | <h2>メールアドレス変更</h2> |
11 | <p>旧メールアドレス <input type='text' id='mail1' /></p> |
12 | <p>新メールアドレス <input type='text' id='mail2' /></p> |
13 | <p>パスワード <input type='password' id='pass1' /> |
14 | <input type='button' id='mailChgExe' value=' 実行 ' /></p> |
15 | ステータス: <nobr id='stat'></nobr> |
16 | <script> |
17 | $('#mailChgExe').click(function(e){ |
18 | var ref = new Firebase('https://fbase-kseino1.firebaseio.com/'); |
19 | ref.changeEmail({ |
20 | oldEmail : $('#mail1').val(), //(1) |
21 | newEmail : $('#mail2').val(), //(2) |
22 | password : $('#pass1').val() //(3) |
23 | }, function(error) { |
24 | if (error === null) { |
25 | $('#stat').text('メールアドレス変更 成功'); |
26 | console.log("Email changed successfully"); |
27 | } else { |
28 | $('#stat').text('メールアドレス変更 不成功'); |
29 | console.log("Error changing email:", error); |
30 | } |
31 | }); |
32 | }); |
33 | </script> |
34 | <hr> |
35 | </body> |
36 | </html> |
パスワードの変更も、リスト8(1)~(3)の処理パターンはこれまでと同じで問題ないでしょう。
リスト8:パスワード変更テンプレート
01 | var ref = new Firebase("https://<your-firebase-app>.firebaseio.com"); |
02 | ref.changePassword({ |
03 | email : "bobtony@firebase.com", //(1) |
04 | oldPassword : "correcthorsebatterystaple", //(2) |
05 | newPassword : "neatsupersecurenewpassword" //(3) |
06 | }, function(error) { |
07 | if (error === null) { |
08 | console.log("Password changed successfully"); |
09 | } else { |
10 | console.log("Error changing password:", error); |
11 | } |
12 | }); |
13 | </your-firebase-app> |
図10のパスワード変更画面も、メールアドレスの変更画面と内容的には同じです。
リスト9では(1)~(3)で画面入力値に置き換えていますが、処理パターンは全く同じです。Firebaseの認証処理については他にも処理項目がありますが、通常の認証処理ではここまで充分でしょう。
リスト9:パスワード変更処理(email-cp.html)
01 | <!DOCTYPE html> |
02 | <html> |
03 | <head> |
04 | <meta charset="utf-8"/> |
05 | <script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script> |
06 | <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> |
07 | <title>パスワード変更</title> |
08 | </head> |
09 | <body bgcolor="#bfefdf"> |
10 | <h2>パスワード変更</h2> |
11 | <p>メール <input type='text' id='email1' /></p> |
12 | <p>旧パスワード <input type='password' id='pass1' /></p> |
13 | <p>新パスワード <input type='password' id='pass2' /> |
14 | <input type='button' id='passChgExe' value=' 実行 ' /></p> |
15 | ステータス: <nobr id='stat'></nobr> |
16 | <script> |
17 | $('#passChgExe').click(function(e){ |
18 | var ref = new Firebase('https://fbase-kseino1.firebaseio.com/'); |
19 | ref.changePassword({ |
20 | email : $('#email1').val(), //(1) |
21 | oldPassword : $('#pass1').val(), //(2) |
22 | newPassword : $('#pass2').val() //(3) |
23 | }, function(error) { |
24 | if (error === null) { |
25 | $('#stat').text('パスワード変更成功:'); |
26 | console.log("Password changed successfully"); |
27 | } else { |
28 | $('#stat').text('パスワード変更不成功:'); |
29 | console.log("Error changing password:", error); |
30 | } |
31 | }); |
32 | }); |
33 | </script> |
34 | <hr> |
35 | </body> |
36 | </html> |
Eclipseでのプログラム作成
Eclipseのプロジェクト構成
ここまでのプログラムはApp Engineのプログラム作成用プラグインがインストールされたEclipseで作成しています。App Engineを使用したFirebaseのプログラム作成については、第3回を参考にしてください。
図11は今回のプロジェクト構成です。第3回でも説明しましたが、Firebaseではサーバ側プログラムが不要なため本来「src」フォルダ下にあるJavaプログラムは削除されています。ただし、web.xml(ディプロイメント・ディスクリプタ:後述)で無視するように指定できるので、Javaプログラムがあっても問題ありません。ここでは解りやすいようにサーバ側のコード(Javaサーブレットおよびビーンズ)はすべて削除しています。
appengine-web.xml
appengine-web.xml(リスト10)では、デフォルトで作成される内容に(1)のapplicationと(2)のversionタグの内容を記述しているだけです。
リスト10:appengine-web.xml
01 | <?xml version="1.0" encoding="utf-8"?> |
02 | <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> |
03 | <application>sonic-solstice-422</application> <!-- (1) --> |
04 | <version>firebase5</version> <!-- (2) --> |
05 |
06 | <!-- |
07 | Allows App Engine to send multiple requests to one instance in parallel: |
08 | --> |
09 | <threadsafe>true</threadsafe> |
10 |
11 | <!-- Configure java.util.logging --> |
12 | <system-properties> |
13 | <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/> |
14 | </system-properties> |
15 | <!-- |
16 | HTTP Sessions are disabled by default. To enable HTTP sessions specify: |
17 | <sessions-enabled>true</sessions-enabled> |
18 | It's possible to reduce request latency by configuring your application to |
19 | asynchronously write HTTP session data to the datastore: |
20 |
21 | <async-session-persistence enabled="true" /> |
22 |
23 | With this feature enabled, there is a very small chance your app will see |
24 | stale session data. For details, see |
25 | http://code.google.com/appengine/docs/java/config/appconfig.html#Enabling_Sessions |
26 | --> |
web.xml(ディプロイメントディスクリプタ)
通常web.xmlにはサーバ側コードに関する内容も記述しますが、今回はコメントアウトではなく、サーバに関するタグ記述をすべて削除しています。これによりweb.xmlの内容はwelcome-fileタグに関する記述のみとなり、非常にシンプルになっています。
リスト11:web.xml
01 | <?xml version="1.0" encoding="utf-8"?> |
02 | <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
03 | xmlns="http://java.sun.com/xml/ns/javaee" |
04 | xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" |
05 | xsi:schemaLocation="http://java.sun.com/xml/ns/javaee |
06 | http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> |
07 | <welcome-file-list> |
08 | <welcome-file>index.html</welcome-file> |
09 | </welcome-file-list> |
10 | </web-app> |
以上の処理で図11のプロジェクトを作成し、App Engineアプリケーションの1つのバージョンとしてディプロイすれば、認証処理の付いたFirebaseチャットとして使用できます。
今回は認証処理について解説しました。昨今は大量のユーザデータ漏えいトラブルが目につき、Firebaseでもセキュリティは必須機能です。
本連載も、次回で最終回となります。Firebaseの最新情報とFarebaseの最大の特徴であるリアルタイムデータベースについて解説します。