Creating and authenticating a user

User model 的基本設定告一段落,現在要建立一個使用者,存進資料庫裡,因為之後要建立使用者個人檔案頁面,會用到使用者的資料。

因為現在還無法直接在 sample APP 的網頁上註冊,所以先使用 Rails console 建立使用者,注意,這時候進入到 console 就不必加上 --sandbox 參數,因為我們要來真的。

方便起見,使用 create 方法建立使用者:

> rails console
> User.create(name: "Luffy Wang", email: "[email protected]", password: "foobar", password_confirmation: "foobar")
=> #<User id: 1, name: "Luffy Wang", email: "[email protected]", created_at: "2016-03-08 05:52:41", updated_at: "2016-03-08 05:52:41", password_digest: "$2a$10$ecVIl7oAqJctPcf7Crnpy.BQrSGGPNGjUvuS2C1DFL8...">

為了確認資料有沒有在開發環境中(development)存進資料庫,可以打開 DB Browser 查看 SQLite:

回到 console,查詢 password_digest 屬性,這就是 has_secure_password 帶來的功用:

> user = User.find_by(email: "[email protected]")
> user.password_digest
=> "$2a$10$ecVIl7oAqJctPcf7Crnpy.BQrSGGPNGjUvuS2C1DFL8e.YLY4mzvW"

這就是用來建立使用者物件時,密碼("foobar")的 hashed value。因為是透過 bcrypt 計算出來,所以很難從 digest 反推回原始的密碼。

bcrypt 演算法會製造出 salted hash ,可以防止兩種攻擊:dictionary attacksrainbow table attacks

之前提到過,has_secure_password 會自動增加一個 authenticate 方法給對應的 model 物件。這個方法會透過使用者提供的密碼計算出 digest,然後跟資料庫裡的 password_digest 做比對來驗證密碼是否正確。

我們可以試試看提供錯誤的密碼會得到什麼結果:

> user.authenticate("not_the_right_password")
=> false
> user.authenticate("foobaz")
=> false

當密碼錯誤,authenticate 會回傳 false,如果正確,會回傳物件本身:

> user.authenticate("foobar")
=> #<User id: 1, name: "Luffy Wang", email: "[email protected]", created_at: "2016-03-08 05:52:41", updated_at: "2016-03-08 05:52:41", password_digest: "$2a$10$ecVIl7oAqJctPcf7Crnpy.BQrSGGPNGjUvuS2C1DFL8...">

後面的章節會使用 authenticate 讓使用者進行註冊,而其實回傳物件本身不是重點,重點是回傳的值為 true,因為使用者物件既不是 nil 或是 false

> !!user.authenticate("foobar")
=> true