【譯】不依賴于Devise模塊如何實現簡單的驗證功能

幾乎每一個web應用都需要表格登錄。在Ruby中,最流行的選擇就是在Rails應用中實用Devise模塊。

Devise提供了許多盒子之外的功能,但這也同樣是令人沮喪的地方。它有很多的“魔法”,并且和Rails的很多功能高度耦合。但是如果你的需求和這個gem并不是很切合,舉例說,匿名用戶-你將需要翻閱整個文檔并且閱讀源碼,來查詢如何實現它。這一點也不可愛,并且看上去一點也不值。如果未來的一段時間內有驗證需求的改變,這個改變對你來說看起來容易實現還是一場噩夢?

驗證事實上是非常簡單的!如果你的需求足夠簡單,你將可以在100行代碼以內實現你的驗證功能。在這片文章中,我將給你展示一個小而美的包含登錄,登出和用戶創建的小的web應用。

所有的源碼都可以在這里找到:
simple_authentication.rb

依賴###

唯一的依賴就是用于創建密碼的BCrypt gem。我們可以直接使用它,在Rails和Devise中都已經默認包含了。

在本例中,我們將使用Sinatra,由于BCrypt 解藕起來非常容易,因此代碼可以輕松地翻譯成Rails,這跟Devise很不一樣。

Gemfile:

source 'https://rubygems.org'
gem 'sinatra', '~>1.4'
gem 'bcrypt', '~>3.1'

BCrypt實現哈希密碼###

需要大約兩行代碼來實現這個需求:

def hash_password(password)
   BCrypt::Password.create(password).to_s
end

def test_password(password, hash)
  BCrypt::Password.new(hash) == password
end

hash_password函數生成了一個普通文本密碼,由單向加密算法加密。要想基于哈希來破解密碼,是一件很困難的、幾乎不可能實現的事情。我們從不存儲密碼,只有哈希。所以,當有黑客進入數據庫的事情發生,我們的密碼依然是手保護的。

test_password函數用于檢測當給定的密碼是否和之前函數給出的hash一致。由于我們不在擁有原始密碼,所以這次通過給定密碼的hash和之前的hash相比較。

這是基本的密碼安全,而這所有的工作都交由bcrypt gem來實現。

User Model###

為了讓本例看起來足夠簡單,User模型只是一個Struct,而“數據庫”就是一個數組。

User = Struct.new(:id, :username, :password_hash)
USERS = [
    User.new(1,'Bob',hash_password('The building'))
    User.new(2, 'Sally', hash_password('go round'))
]

每個用戶都只有三個基本屬性:id,username,hash。如果這是在Rails當中,你可以創建一個只有這三個屬性的模型。

Signing In###

下列代碼運行于用戶提交登錄表格:

post '/sign_in' do
   user = USERS.find{ |u| u.username == params[:username]}
    if user && test_password(params[:password],user.password_hash)
        session.clear
        session[:user_id] = user.id
        redirect '/'
     else
        @error = 'Username or password was incorrect'
        erb :sign_in
     end
end

安全須知:一旦成功登錄,我們在存儲用戶名之前情調session,這是一種阻止Session Fixation Attacks的安全策略

訪問當前用戶###

一旦用戶登入,我們需要知道未來誰來在發送請求。下述代碼可以返回當前用戶:

    def current_user
        if session[:user_id]
          USERS.find { |u| u.id == session[:user_id] }
        else
           nil
         end
      end

當我們在登入狀態時,檢查session是否包含user id,當user id存在時,根據用戶id找到user。如果是在Rails當中,又可以用User.find(session[:user_id]).

在主頁中,我們可以使用current_user:

<p>Hello, <%= current_user.username %></p>

Signing Out###

如下:

post '/sign_out' do
    session.clear
    redirect '/sign_in'
end

由于用戶id存儲在session中,我們只需要清除session來sign out。簡單而又優美!

創建一個新用戶###

代碼如下:

post '/create_user' do
    USERS << User.new(
        USERS.size + 1,
        params[:username],
        hash_password(params[:password])
    )
    redirect '/'
end

在這個小小的實例中,我們創建了一個User對象,并將它添加到user數組中。

結束語###

擁有一個基本驗證的工作實例一點也不難,不是嗎?

原文How To Implement Simple Authentication Without Devise

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.caching with instance variables2.dynamic find_by method...
    Jayzen閱讀 1,417評論 0 1
  • devise是一個很好的用戶登錄gem。但還是想自己寫個“輪子”,一則本來就是在學習rails,二則是了解了用戶登...
    kamionayuki閱讀 6,284評論 2 9
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,767評論 18 399
  • 1.Environment Variables [finish] 2.Ruby Version Managers ...
    Jayzen閱讀 1,286評論 0 1
  • 準備工具 ruby v2.2.6rails v5.0.0.1 開整 新建項目 rails new blog 進入目...
    ahtest閱讀 1,417評論 0 3