【備忘録】BCryptを使ったRails+MongoDBでのパスワード暗号化

パスワードとかを暗号化する際にBCryptを良さげなので
Rails+MongoDBでの導入方法から使用方法まで

やりたいこと
---
Rails+MongoDBでパスワードフィールド(RDBでいう属性、カラム)とか
生で保存したくないデータを暗号化したいとき

BCryptとは
---
認証で使用するパスワードを安全にハッシュ化するアルゴリズム。
SHA256等では暗号化として不足するため(下記参照)、
saltと呼ばれる短いランダムな文字列を末尾に加えて暗号化する。
レインボーテーブル(ハッシュ値に対して総当たりで平文を得ようとする)に対して強力のようです

[BCryptのすすめ](https://qiita.com/ponkotuy/items/1a703b866ddf5c9fe80c)
>よくあるHash関数アルゴリズムは(元々高速に計算することを意図していたのもあり)非常に高速に計算が可能であり、総当たり試行されてしまえば、現代のコンピュータスペックをもってすれば一瞬で解読されてしまいます。また、レインボーテーブルと呼ばれる、高速にHashから元の値を類推することが可能なアルゴリズムも存在し、Hash化では不足です。

インストール
---
Gemfileに下記を追加し、`bundle install`でインストールできます

```Gemfile
# パスワード暗号化Gem
gem 'bcrypt', '~> 3.1.11'
```

モデル処理
---
app/models内の暗号化したいフィールド(属性、カラム)があるモデルについて
下記の様に`has_secure_password`メソッドを使用します。

```rb
class Hoge
  # has_secure_passwordが存在しない。というエラーが発生したら追加します
  include ActiveModel::SecurePassword

  # パスワード暗号化
  has_secure_password

end
```

Hogeモデルにpassword_confirmationフィールドが追加され、
validateも自動で追加されます。
authenticateメソッドが使えるようになります


なおRDBの場合、password_digest属性の追加されたことにより
マイグレーションが必要になります。
(MongoDB等のNoSQLの場合不要です)

ViewおよびControllersでの使用方法
---
View側でpasswordをform_tagで送り、Controllersでドキュメント(行、レコード)を追加することで
こうすることでbcryptがpassword_digestフィールドに暗号化されたパスワードを入れます。
Controllers側では暗号化に関わる処理は特に何もする必要はないです。

以下ユーザ登録フォームでの使用方法例

例
![スクリーンショット 2018-12-08 13.22.33.png](https://qiita-image-store.s3.amazonaws.com/0/238856/b9bc99e8-508d-2a86-446e-140e90fbb14a.png)


app/views/userCreate.erb

```erb
            <h4 class="">ユーザー登録</h4>
            <%= form_tag("/user/create") do%>
                    <p class ="">名前</p>
                    <input class="" name = "name">
                    <p class ="">Eメール</p>
                    <input class="" name = "email">
                    <p class ="">パスワード</p>
                    <input type="password" class="" name ="password">
                    <div class="">
                        <input type="submit" class="btn btn-primary" value="登録">
                     </div>
            <% end %>
```


/config/route.rb

```rb
post "/user/create" => "user#userCreate"
```

app/controllers/user_controller.rb

```rb
    def userSignUp
        @user = User.new
    end
```

パスワード認証方法
---
先ほどは暗号化したパスワードを格納しましたが、
今度はパスワードを画面入力した際など、画面から生のパスワードデータがきたときのControllers側の処理はauthenticateメソッドを利用します。

以下、ログイン画面を想定した使用例です

![スクリーンショット 2018-12-08 13.21.21.png](https://qiita-image-store.s3.amazonaws.com/0/238856/a77fc5b1-c694-543b-3366-3d389e71b1a2.png)

/app/views/login.erb

```erb
 <%= form_tag("/user/login") do%>
  　<p class="">ユーザ名</p>
    <input class="w-150" name="name">
  　<p class="">パスワード</p>
    <input type="password" class="" name="password">
    <div class="">
      <input type="submit" class="btn btn-primary" value="ログイン">
    </div>
```

/config/route.rb

```rb
post "/user/login" => "user#userLogin"
```

app/controllers/user_controller.rb

```rb
    def userLogin
        @user = Hoge.find_by(name: params[:name])
        # @user.authenticateで入力されたパスワードを暗号化した後に
        # password_digestフィールドと比較
        if @user && @user.authenticate(params[:password])
            flash[:notice] = "ログインしました"
            redirect_to("/Fuga")
        else
            @errorMessage = "ログインに失敗"
            render("/login")
        end

    end
```



参照
---
[Railsにおけるパスワードの扱い方(BCrypt)](https://qiita.com/tatane616/items/c00182179e498aa9c53e)
[BCryptのすすめ](https://qiita.com/ponkotuy/items/1a703b866ddf5c9fe80c)
どちらもありがとうございます。