45
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Firebaseを色々ためそう

Last updated at Posted at 2016-11-26

#1.Firebaseの利用開始

とりあえずここから新規登録してね
※Googleアカウントが必要だよ
https://console.firebase.google.com/

##新規プロジェクトを作成
ログインできたら、「新規プロジェクトを作成」ボタンから
新規プロジェクトを作ろう

※国はまぁ、日本人なんで日本選ぼう

これでプロジェクトできたね!早いね!

#2.デプロイしてみよう

##Firebase toolsをインストールしよう

npmでFirebase toolsをインストール
npmがない人はnode.jsをインストールしてね。

command

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

brew install nodebrew

nodebrew install-binary latest

npm install -g firebase-tools

##コードを書くためのディレクトリを用意しよう

適当なディレクトリを作ったら、コマンドラインでそこに移動して
以下のコマンドを打ってください。

command
firebase login

そしたらなんかブラウザが起動するのでFirebaseの登録に使った
Googleアカウントでブラウザからログインしてください

次に以下のコマンドを打ってください

command
firebase init

色々聞かれるので
What Firebase CLI features do you want to setup for this folder?
→これはそのままEnter

Project Setup
→さっき作ったFirebaseプロジェクトを選択

Database Setup
→これはそのままEnter

What do you want to use as your public directory?
→これはyを選択しEnter

Configure as a single-page app (rewrite all urls to /index.html)?
→これもyを選択しEnter

これで色々ファイルが勝手に作成されました!

public
└index.html
database.rules.json
firebase.json

publicフォルダの下に作られたindex.htmlを適当にいじってください。
とりあえずh1タグの中身かえるとか。

そしてデプロイコマンドを叩けば、デプロイ完了です。

command
firebase deploy

このコマンドを叩くと、太字でHosting URLという項目が表示されます。
このURLが今デプロイしたサイトのURLになります。
アクセスしてみよう。

#3.データベースを使ってみよう

Consoleの「Database」ってとこをクリックしてみよう。
まだ何もないね!

##セキュリティルールを解放しろ!
「既定のセキュリティ ルールではユーザーの認証が必要です」って青文字が出てます。
このままだとユーザー認証とかしないとデータベースが使えないんですね。
なので「ルール」ってタブをクリックしてくださいね。
そしたら以下のような感じになってるのがわかりますね。

rule.json
{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}

これを

rule.json
{
  "rules": {
    ".read": true,
    ".write": true
  }
}

こうしちゃおう
そして「公開」ボタンを押せば・・・
「セキュリティ ルールが公開対象として定義されているため、誰でもデータベースの読み取りや書き込みを行えます」
みたいなのが赤文字で出てきましたね。
これでユーザー認証なしでDBが使えるようになってしまいました!

※ここのルールと「database.rules.json」で定義したルールは、プロジェクトのデプロイ時に同期されます。
「database.rules.json」の内容で上書きされるので注意が必要です。
というか実際は「database.rules.json」を正として開発するのが正しいですね。

##コードを書こう
publicディレクトリ内のindex.htmlを以下の内容に書き換えてください。
※jQueryを使用しています。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Firebase Study</title>
    <style media="screen">
    </style>
  </head>
  <body>
    <form id="input_form">
        <input type="text" id="name" size="10" placeholder="Name" value="名無し">
        <input type="text" id="input_text" size="50">
        <button type="submit" id="send_btn">SEND</button>
        <hr>
        <div id="chat_area"></div>
    </form>
  </body>
  <script
    src="https://code.jquery.com/jquery-2.2.4.min.js"
    integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
    crossorigin="anonymous"></script>
  <script src="https://www.gstatic.com/firebasejs/3.6.1/firebase.js"></script>
  <script>
    $(function(){
      // ↓↓↓ここの情報を自分のプロジェクトのものに置き換えてください
      // Initialize Firebase
      var config = {
        apiKey: '<your-api-key>',
        authDomain: '<your-auth-domain>',
        databaseURL: '<your-database-url>',
        storageBucket: '<your-storage-bucket>'
      };
      // ↑↑↑ここの情報を自分のプロジェクトのものに置き換えてください
      firebase.initializeApp(config);

      // submit時
      $("#input_form").submit(function(){
          writeChatData($("#name").val(), $("#input_text").val());
          return false;
      });

      // 発言を登録
      function writeChatData(name, text) {
        $("#input_text").val("");
        firebase.database().ref('chat').push({
          name: name,
          text: text
        });
      }

      // 発言を表示
      firebase.database().ref("chat").on("value", function(snapshot) {
          $("#chat_area").html("");

          var logs = snapshot.val();
          for (var key in logs) {
              var logHtml = '<p>' + logs[key].name + '' + logs[key].text + '</p><hr>'
              $("#chat_area").prepend(logHtml);
          }
      });

    });

  </script>
</html>

configを自分のプロジェクトの設定に変更してください。
ダッシュボードを開き、トップの右側にある「ウェブアプリにFirebaseを追加」のアイコンをクリックすると、そのプロジェクトのconfigが表示されます。

##実行しよう

以下のコマンドを打つと、ローカルでサーバーが起動します。

command
firebase serve

localhost:5000にアクセスすると、作成したチャット画面が表示されます。

#4.認証機能を使おう

##まずはダッシュボードでAuthenticationの設定
「Authentication」メニューをクリックし、「ログイン方法」タブを選択してください。
「メール/パスワード」が無効になっていると思いますので、
有効にして保存してください。

##コードを変更

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Firebase Study</title>
    <style media="screen">
     /** ↓↓4.認証で追加↓↓ */
      body {
        margin: 0;
        padding: 0;
      }
      header {
        background: #f99;
        padding: 10px;
        text-align: right;
      }
      #input_form {
        padding: 10px;
      }
     /** ↑↑4.認証で追加↑↑ */
    </style>
  </head>
  <body>
    <!-- ↓↓4.認証で追加↓↓ -->
    <header>
      <div id="login_info">
        <input type="email" id="email" placeholder="email">
        <input type="password" id="password" placeholder="password">
        <button id="login_btn">ログイン</button>
        <button id="user_regist_btn">新規登録</button>
      </div>
      <div id="logout_info" style="display: none;">
        <button id="logout_btn">ログアウト</button>
      </div>
    </header>
    <!-- ↑↑4.認証で追加↑↑ -->
    <form id="input_form">
        <input type="text" id="name" size="10" placeholder="Name" value="名無し">
        <input type="text" id="input_text" size="50">
        <button type="submit" id="send_btn">SEND</button>
        <hr>
        <div id="chat_area"></div>
    </form>
  </body>
  <script
    src="https://code.jquery.com/jquery-2.2.4.min.js"
    integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
    crossorigin="anonymous"></script>
  <script src="https://www.gstatic.com/firebasejs/3.6.1/firebase.js"></script>
  <script>
    $(function(){
      // ↓↓↓ここの情報を自分のプロジェクトのものに置き換えてください
      // Initialize Firebase
      var config = {
        apiKey: '<your-api-key>',
        authDomain: '<your-auth-domain>',
        databaseURL: '<your-database-url>',
        storageBucket: '<your-storage-bucket>'
      };
      // ↑↑↑ここの情報を自分のプロジェクトのものに置き換えてください
      firebase.initializeApp(config);

      // submit時
      $("#input_form").submit(function(){
          writeChatData($("#name").val(), $("#input_text").val());
          return false;
      });

      // 発言を登録
      function writeChatData(name, text) {
        $("#input_text").val("");
        firebase.database().ref('chat').push({
          name: name,
          text: text
        });
      }

      // 発言を表示
      firebase.database().ref("chat").on("value", function(snapshot) {
          $("#chat_area").html("");

          var logs = snapshot.val();
          for (var key in logs) {
              var logHtml = '<p>' + logs[key].name + '' + logs[key].text + '</p><hr>'
              $("#chat_area").prepend(logHtml);
          }
      });

      //↓↓4.認証で追加↓↓
      firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
          $("#login_info").hide();
          $("#logout_info").show();
          if (user.displayName) {
            $("#name").val(user.displayName);
          }
        } else {
          $("#logout_info").hide();
          $("#login_info").show();
          $("#name").val("");
        }
      });

      // ユーザー登録
      $("#user_regist_btn").click(function(){
        var email = $("#email").val();
        var password = $("#password").val();
        firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          alert(errorMessage);
        });
      });

      // ログイン
      $("#login_btn").click(function(){
        var email = $("#email").val();
        var password = $("#password").val();
        firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          alert(errorMessage);
        });
      });

      // ログアウト
      $("#logout_btn").click(function(){
        firebase.auth().signOut().then(function() {
          // Sign-out successful.
        }, function(error) {
          // An error happened.
        });
      });

      // 名前が変更されたらプロフィールを変更
      $("#name").change(function(){
        var user = firebase.auth().currentUser;
        if (user) {
          user.updateProfile({
            displayName: $("#name").val()
          });
        }
      });

      //↑↑4.認証で追加↑↑

    });

  </script>
</html>

##GoogleやFacebookアカウントで認証したい
ここまでわかればあとはドキュメント見れば大丈夫

https://firebase.google.com/docs/auth/web/google-signin
https://firebase.google.com/docs/auth/web/facebook-login

#5.セキュリティルールを設定しよう
せっかくログイン機能作ったけど、誰でも書き込めるしあんま意味ないよね。
なのでセキュリティルールを設定してみましょう

##ログインしてないと書き込み禁止にする
database.rules.jsonをいじろう

database.rules.json
{
  "rules": {
    ".read": true,
    ".write": "auth != null"
  }
}

エラーをわかりやすくするためindex.htmlもちょこっとだけいじる
※発言を登録するメソッドにcatchの部分を追加

index.html
      // 発言を登録
      function writeChatData(name, text) {
        $("#input_text").val("");
        firebase.database().ref('chat').push({
          name: name,
          text: text
        }).catch(function(error) {
          alert(error.message);
        });
      }

そしたらデプロイ

command
firebase deploy

ログインしないと書き込めなくなりましたね

##もっと難しいルールを
自分の発言だけを変更可能にする

database.rules.json
{
  "rules": {
    "chat": {
      ".read": true,
      "$message": {
        ".write": "data.child('user_id').val() == auth.uid || !data.exists()"
      }
    }
  }
}

dataは変更前のデータを表します。
authはログインユーザーの情報を表しています。
$messageはchat要素の子供の要素を表しています。

$につづく名前はなんでもいいです。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Firebase Study</title>
    <style media="screen">
     /** ↓↓4.認証で追加↓↓ */
      body {
        margin: 0;
        padding: 0;
      }
      header {
        background: #f99;
        padding: 10px;
        text-align: right;
      }
      #input_form {
        padding: 10px;
      }
    </style>
  </head>
  <body>
    <!-- ↓↓4.認証で追加↓↓ -->
    <header>
      <div id="login_info">
        <input type="email" id="email" placeholder="email">
        <input type="password" id="password" placeholder="password">
        <button id="login_btn">ログイン</button>
        <button id="user_regist_btn">新規登録</button>
      </div>
      <div id="logout_info" style="display: none;">
        <button id="logout_btn">ログアウト</button>
      </div>
    </header>
    <!-- ↑↑4.認証で追加↑↑ -->
    <form id="input_form">
        <input type="text" id="name" size="10" placeholder="Name" value="名無し">
        <input type="text" id="input_text" size="50">
        <button type="submit" id="send_btn">SEND</button>
        <hr>
        <div id="chat_area"></div>
    </form>
  </body>
  <script
    src="https://code.jquery.com/jquery-2.2.4.min.js"
    integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
    crossorigin="anonymous"></script>
  <script src="https://www.gstatic.com/firebasejs/3.6.1/firebase.js"></script>
  <script>
    $(function(){
      // ↓↓↓ここの情報を自分のプロジェクトのものに置き換えてください
      // Initialize Firebase
      var config = {
        apiKey: '<your-api-key>',
        authDomain: '<your-auth-domain>',
        databaseURL: '<your-database-url>',
        storageBucket: '<your-storage-bucket>'
      };
      // ↑↑↑ここの情報を自分のプロジェクトのものに置き換えてください
      firebase.initializeApp(config);
      
      var userId = "";

      // submit時
      $("#input_form").submit(function(){
          writeChatData($("#name").val(), $("#input_text").val());
          return false;
      });

      // 発言を登録
      function writeChatData(name, text) {
        $("#input_text").val("");
        firebase.database().ref('chat').push({
          name: name,
          text: text,
          user_id: userId   // ←5.セキュリティルールで変更
        }).catch(function(error) {
          alert(error.message);
        });
      }

      //↓↓5.セキュリティルールで変更↓↓
      // 発言を更新
      function updateChatData(key, text) {
        firebase.database().ref('chat/' + key + '/text').set(text).catch(function(error) {
          alert(error.message);
        });
      }
      //↑↑5.セキュリティルールで変更↑↑

      // 発言を表示
      firebase.database().ref("chat").on("value", function(snapshot) {
          $("#chat_area").html("");

          var logs = snapshot.val();
          for (var key in logs) {
              var logHtml = '';
              //↓↓5.セキュリティルールで変更↓↓
              if (logs[key].user_id == userId) {
                logHtml = '<p>' + logs[key].name + ':<input type="text" class="update_text" size="50" value="' + logs[key].text + '" data-key="' + key + '"/></p><hr>'
              } else {
                logHtml = '<p>' + logs[key].name + '' + logs[key].text + '</p><hr>'
              }
              //↑↑5.セキュリティルールで変更↑↑

              $("#chat_area").prepend(logHtml);
          }

          //↓↓5.セキュリティルールで変更↓↓
          $(".update_text").off("change");
          $(".update_text").on("change", function(){
            var key = $(this).attr("data-key");
            var text = $(this).val();
            updateChatData(key, text);
          });
          //↑↑5.セキュリティルールで変更↑↑

      });

      //↓↓4.認証で追加↓↓
      firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
          $("#login_info").hide();
          $("#logout_info").show();
          if (user.displayName) {
            $("#name").val(user.displayName);
          }
          userId = user.uid;
        } else {
          $("#logout_info").hide();
          $("#login_info").show();
          $("#name").val("");
        }
      });

      // ユーザー登録
      $("#user_regist_btn").click(function(){
        var email = $("#email").val();
        var password = $("#password").val();
        firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          alert(errorMessage);
        });
      });

      // ログイン
      $("#login_btn").click(function(){
        var email = $("#email").val();
        var password = $("#password").val();
        firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          alert(errorMessage);
        });
      });

      // ログアウト
      $("#logout_btn").click(function(){
        firebase.auth().signOut().then(function() {
          // Sign-out successful.
        }, function(error) {
          // An error happened.
        });
      });

      // 名前が変更されたらプロフィールを変更
      $("#name").change(function(){
        var user = firebase.auth().currentUser;
        if (user) {
          user.updateProfile({
            displayName: $("#name").val()
          });
        }
      });

      //↑↑4.認証で追加↑↑

    });

  </script>
</html>

#6.ストレージを使おう

FirebaseからGCPのGoogle Cloud Storageを使うことができます。
こんな感じで書けばファイルをアップロードできます

upload
var storageRef = firebase.storage().ref();
var uploadTask = storageRef.child('images/' + userId + '/' + file.name).put(file);

ログインしたユーザーのアイコン画像をアップロードして
発言と一緒にアイコンも表示されるようにしてみよう

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Firebase Study</title>
    <style media="screen">
     /** ↓↓4.認証で追加↓↓ */
      body {
        margin: 0;
        padding: 0;
      }
      header {
        background: #f99;
        padding: 10px;
        text-align: right;
      }
      #input_form {
        padding: 10px;
      }
      #user_icon {
        height: 60px;
      }
    </style>
  </head>
  <body>
    <!-- ↓↓4.認証で追加↓↓ -->
    <header>
      <div id="login_info">
        <input type="email" id="email" placeholder="email">
        <input type="password" id="password" placeholder="password">
        <button id="login_btn">ログイン</button>
        <button id="user_regist_btn">新規登録</button>
      </div>
      <div id="logout_info" style="display: none;">
        <!-- ↓↓6.ストレージで追加↓↓ -->
        <input type="file" id="icon_file"><button id="icon_up_btn">アイコン画像をアップロード</button>
        <!-- ↑↑6.ストレージで追加↑↑ -->
        <button id="logout_btn">ログアウト</button>
      </div>
    </header>
    <!-- ↑↑4.認証で追加↑↑ -->
    <form id="input_form">
        <!-- ↓↓6.ストレージで追加↓↓ -->
        <img src="" id="user_icon">
        <!-- ↑↑6.ストレージで追加↑↑ -->
        <input type="text" id="name" size="10" placeholder="Name" value="名無し">
        <input type="text" id="input_text" size="50">
        <button type="submit" id="send_btn">SEND</button>
        <hr>
        <div id="chat_area"></div>
    </form>
  </body>
  <script
    src="https://code.jquery.com/jquery-2.2.4.min.js"
    integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
    crossorigin="anonymous"></script>
  <script src="https://www.gstatic.com/firebasejs/3.6.1/firebase.js"></script>
  <script>
    $(function(){
      // ↓↓↓ここの情報を自分のプロジェクトのものに置き換えてください
      // Initialize Firebase
      var config = {
        apiKey: "AIzaSyDFWFBb2ZsPoN3q7Y-KnOp_xboLvBPmK-Q",
        authDomain: "fb-hack-fa53d.firebaseapp.com",
        databaseURL: "https://fb-hack-fa53d.firebaseio.com",
        storageBucket: "fb-hack-fa53d.appspot.com",
        messagingSenderId: "462609738357"
      };
      // ↑↑↑ここの情報を自分のプロジェクトのものに置き換えてください
      firebase.initializeApp(config);
      
      var userId = "";

      // submit時
      $("#input_form").submit(function(){
          writeChatData($("#name").val(), $("#input_text").val());
          return false;
      });

      // 発言を登録
      function writeChatData(name, text) {
        $("#input_text").val("");
        firebase.database().ref('chat').push({
          name: name,
          text: text,
          user_id: userId,   // ←5.セキュリティルールで変更
          photo_url: $("#user_icon").attr("src") // ←6.ストレージで変更
        }).catch(function(error) {
          alert(error.message);
        });
      }

      //↓↓5.セキュリティルールで変更↓↓
      // 発言を更新
      function updateChatData(key, text) {
        firebase.database().ref('chat/' + key + '/text').set(text).catch(function(error) {
          alert(error.message);
        });
      }
      //↑↑5.セキュリティルールで変更↑↑

      // 発言を表示
      firebase.database().ref("chat").on("value", function(snapshot) {
          $("#chat_area").html("");

          var logs = snapshot.val();
          for (var key in logs) {
              var logHtml = '';
              //↓↓5.セキュリティルールで変更↓↓
              var photoUrl = logs[key].photo_url; // 6.ストレージで変更
              if (!photoUrl) photoUrl = "";     // 6.ストレージで変更
              if (logs[key].user_id == userId) {
                 // 6.ストレージで変更
                logHtml = '<p><img src="' + photoUrl + '" height="40px">' + logs[key].name + ':<input type="text" class="update_text" size="50" value="' + logs[key].text + '" data-key="' + key + '"/></p><hr>'
              } else {
                 // 6.ストレージで変更
                logHtml = '<p><img src="' + photoUrl + '" height="40px">' + logs[key].name + '' + logs[key].text + '</p><hr>'
              }
              //↑↑5.セキュリティルールで変更↑↑

              $("#chat_area").prepend(logHtml);
          }

          //↓↓5.セキュリティルールで変更↓↓
          $(".update_text").off("change");
          $(".update_text").on("change", function(){
            var key = $(this).attr("data-key");
            var text = $(this).val();
            updateChatData(key, text);
          });
          //↑↑5.セキュリティルールで変更↑↑

      });

      //↓↓4.認証で追加↓↓
      firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
          $("#login_info").hide();
          $("#logout_info").show();
          if (user.displayName) {
            $("#name").val(user.displayName);
          }
          //↓↓6.ストレージで追加↓↓
          if (user.photoURL) {
            $("#user_icon").attr("src", user.photoURL);
          }
          //↑↑6.ストレージで追加↑↑
          userId = user.uid;
        } else {
          $("#logout_info").hide();
          $("#login_info").show();
          $("#name").val("");
        }
      });

      // ユーザー登録
      $("#user_regist_btn").click(function(){
        var email = $("#email").val();
        var password = $("#password").val();
        firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          alert(errorMessage);
        });
      });

      // ログイン
      $("#login_btn").click(function(){
        var email = $("#email").val();
        var password = $("#password").val();
        firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          alert(errorMessage);
        });
      });

      // ログアウト
      $("#logout_btn").click(function(){
        firebase.auth().signOut().then(function() {
          // Sign-out successful.
        }, function(error) {
          // An error happened.
        });
      });

      // 名前が変更されたらプロフィールを変更
      $("#name").change(function(){
        var user = firebase.auth().currentUser;
        if (user) {
          user.updateProfile({
            displayName: $("#name").val()
          });
        }
      });

      //↑↑4.認証で追加↑↑

      //↓↓6.ストレージで追加↓↓
      $("#icon_up_btn").click(function(){
        var file = $('#icon_file')[0].files[0];
        if (!file) return false;

        var storageRef = firebase.storage().ref();
        var uploadTask = storageRef.child('images/' + userId + '/' + file.name).put(file);

        uploadTask.on('state_changed', function(snapshot){
          // アップロード中のステータスが変わったときに何かする場所
        }, function(error) {
          alert("アップロードに失敗しました");
        }, function() {
          var iconURL = uploadTask.snapshot.downloadURL;
          console.log(iconURL);
          $('#icon_file').val("");
          alert("アップロード完了");

          // ユーザーのアイコン画像に設定
          var user = firebase.auth().currentUser;
          if (user) {
            user.updateProfile({
              photoURL: iconURL
            });
          }
          $("#user_icon").attr("src", iconURL);

        });
      });
      //↑↑6.ストレージで追加↑↑
      
    });

  </script>
</html>

とりあえず以上です。
お疲れ様でした。

今回のソース
https://github.com/nakazonor/firebase-study

45
52
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?