Devise 是一個基於 Warden 的靈活的 Rails 身份驗證解決方案。它:
它由10個模組組成:
Devise Wiki 有大量有關 Devise 的附加信息,包括許多「如何做」文章以及最常見問題的解答。完成本 README 後請瀏覽 Wiki:
https://github.com/heartcombo/devise/wiki
如果您發現 Devise 有問題,我們很想知道。但是,我們要求您在提交錯誤報告之前查看這些指南:
https://github.com/heartcombo/devise/wiki/Bug-reports
如果您發現了與安全相關的錯誤,請不要使用 GitHub 問題追蹤器。發送電子郵件至 [email protected]。
如果您有任何問題、意見或疑慮,請使用 StackOverflow 而不是 GitHub 問題追蹤器:
http://stackoverflow.com/questions/tagged/devise
仍然可以閱讀已棄用的郵件列表
https://groups.google.com/group/plataformatec-devise
您可以在此處查看 RDoc 格式的 Devise 文件:
http://rubydoc.info/github/heartcombo/devise/main/frames
如果您需要將 Devise 與先前版本的 Rails 一起使用,您始終可以在安裝 gem 後從命令列執行「gem server」來存取舊文件。
GitHub 上提供了一些範例應用程序,它們示範了 Devise 與不同版本的 Rails 的各種功能。您可以在這裡查看它們:
https://github.com/heartcombo/devise/wiki/Example-Applications
我們的社群創建了許多擴展,這些擴展添加了超出 Devise 所包含功能的功能。您可以在此處查看可用擴充功能列表並添加您自己的擴充功能:
https://github.com/heartcombo/devise/wiki/Extensions
我們希望您考慮為 Devise 做出貢獻。請閱讀此簡短概述,以了解有關如何開始的一些資訊:
https://github.com/heartcombo/devise/wiki/Contributing
您通常需要為您的更改編寫測試。要運行測試套件,請進入 Devise 的頂級目錄並運行bundle install
和bin/test
。 Devise 可與多個 Ruby 和 Rails 版本以及 ActiveRecord 和 Mongoid ORM 搭配使用,這表示您可以使用一些修飾符來執行測試套件: DEVISE_ORM
和BUNDLE_GEMFILE
。
由於 Devise 同時支援 Mongoid 和 ActiveRecord,因此我們依靠此變數來為每個 ORM 執行特定程式碼。 DEVISE_ORM
的預設值為active_record
。要執行 Mongoid 測試,您可以傳遞mongoid
:
DEVISE_ORM=mongoid bin/test
==> Devise.orm = :mongoid
執行 Mongoid 測試時,您的系統上需要執行 MongoDB 伺服器(2.0 版或更高版本)。
請注意,命令輸出將顯示正在使用的變數值。
我們可以使用此變數告訴捆綁程式應該使用什麼 Gemfile(而不是目前目錄中的 Gemfile)。在 gemfiles 目錄中,我們支援的每個版本的 Rails 都有一個。當您向我們發送拉取請求時,測試套件可能會因使用其中某些請求而中斷。如果是這種情況,您可以使用BUNDLE_GEMFILE
變數來模擬相同的環境。例如,如果使用 Ruby 3.0.0 和 Rails 6.0 的測試失敗,您可以執行下列操作:
rbenv shell 3.0.0 # or rvm use 3.0.0
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-6-0 bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-6-0 bin/test
如果 Mongoid 的測試失敗,您也可以將它們結合起來:
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-6-0 bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-6-0 DEVISE_ORM=mongoid bin/test
Devise 使用 Mini Test 作為測試框架。
bin/test
bin/test test/models/trackable_test.rb
bin/test test/models/trackable_test.rb:16
如果您正在建立第一個 Rails 應用程序,我們建議您不要使用 Devise。 Devise 需要對 Rails 框架有很好的理解。在這種情況下,我們建議您從頭開始一個簡單的身份驗證系統。以下是一些可以幫助您入門的資源:
一旦您鞏固了對 Rails 和身份驗證機制的理解,我們向您保證與 Devise 合作將會非常愉快。 ?
Devise 4.0 可與 Rails 6.0 以上版本搭配使用。跑步:
bundle add devise
接下來,您需要運行生成器:
rails generate devise:install
此時,控制台中會出現一些指令。在這些說明中,您需要為每個環境中的 Devise 郵件程式設定預設 URL 選項。這是config/environments/development.rb
的可能設定:
config . action_mailer . default_url_options = { host : 'localhost' , port : 3000 }
生成器將安裝一個初始化程序,該初始化程序描述了 Devise 的所有配置選項。你有必要看一下它。完成後,您就可以使用生成器將 Devise 新增到任何模型中。
在以下命令中,您將用應用程式使用者使用的類別名稱來取代MODEL
(通常是User
但也可以是Admin
)。這將創建一個模型(如果不存在)並使用預設的 Devise 模組對其進行配置。生成器也會配置您的config/routes.rb
檔案以指向 Devise 控制器。
rails generate devise MODEL
接下來,檢查模型以了解您可能想要新增的任何其他配置選項,例如可確認或可鎖定。如果新增選項,請務必檢查移轉檔案(如果您的 ORM 支持,則由生成器建立)並取消註釋相應的部分。例如,如果您在模型中新增可確認選項,則需要在遷移中取消註解可確認部分。
然後運行rails db:migrate
更改 Devise 的配置選項(包括停止 spring)後,您應該重新啟動應用程式。否則,您將遇到奇怪的錯誤,例如,使用者無法登入和路由助手未定義。
Devise 將建立一些幫助器以在控制器和視圖中使用。要設定具有使用者身份驗證的控制器,只需新增此 before_action (假設您的裝置模型是「使用者」):
before_action :authenticate_user!
對於 Rails 5,請注意, protect_from_forgery
不再新增至before_action
鏈之前,因此,如果您在protect_from_forgery
之前設定了authenticate_user
,則您的請求將導致「無法驗證 CSRF 令牌真實性」。若要解決此問題,請變更呼叫它們的順序,或使用protect_from_forgery prepend: true
。
如果您的設備型號不是 User,請將“_user”替換為“_yourmodel”。相同的邏輯適用於以下說明。
若要驗證使用者是否已登錄,請使用以下說明程式:
user_signed_in?
對於目前登入的用戶,可以使用此幫助程式:
current_user
您可以存取此範圍的會話:
user_session
登入使用者、確認帳戶或更新密碼後,Devise 會尋找要重新導向的作用域根路徑。例如,當使用:user
資源時,如果user_root_path
存在,則會使用它;否則,將使用預設的root_path
。這意味著您需要在路由中設定根:
root to : 'home#index'
您也可以覆寫after_sign_in_path_for
和after_sign_out_path_for
來自訂重定向掛鉤。
請注意,例如,如果您的 Devise 模型名為Member
而不是User
,則可用的幫助程式為:
before_action :authenticate_member!
member_signed_in?
current_member
member_session
模型中的 Devise 方法也接受一些選項來配置其模組。例如,您可以透過以下方式選擇雜湊演算法的成本:
devise :database_authenticatable , :registerable , :confirmable , :recoverable , stretches : 13
除了:stretches
之外,您還可以定義:pepper
、 :encryptor
、 :confirm_within
、 :remember_for
、 :timeout_in
、 :unlock_in
等選項。有關更多詳細信息,請參閱調用上述“devise:install”生成器時創建的初始化程序文件。該檔案通常位於/config/initializers/devise.rb
。
Devise 4 的 Parameter Sanitizer API 已更改
先前的 Devise 版本,請參閱 https://github.com/heartcombo/devise/tree/3-stable#strong-parameters
當您自訂自己的視圖時,您最終可能會在表單中新增屬性。 Rails 4 將參數清理從模型移至控制器,使 Devise 也在控制器上處理此問題。
Devise 中只有三個操作允許將任何參數集傳遞到模型,因此需要清理。它們的名稱和預設允許的參數是:
sign_in
( Devise::SessionsController#create
) - 僅允許驗證金鑰(例如email
)sign_up
( Devise::RegistrationsController#create
) - 允許驗證金鑰以及password
和password_confirmation
account_update
( Devise::RegistrationsController#update
) - 允許身分驗證金鑰加上password
、 password_confirmation
和current_password
如果您想要允許其他參數(惰性方式™),您可以在ApplicationController
中使用簡單的 before 操作來實現:
class ApplicationController < ActionController :: Base
before_action :configure_permitted_parameters , if : :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer . permit ( :sign_up , keys : [ :username ] )
end
end
以上適用於參數為簡單標量類型的任何其他欄位。如果您有巢狀屬性(假設您正在使用accepts_nested_attributes_for
),那麼您需要告訴 devise 這些巢狀和類型:
class ApplicationController < ActionController :: Base
before_action :configure_permitted_parameters , if : :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer . permit ( :sign_up , keys : [ :first_name , :last_name , address_attributes : [ :country , :state , :city , :area , :postal_code ] ] )
end
end
Devise 可讓您完全變更 Devise 預設值或透過傳遞區塊來呼叫自訂行為:
若要允許使用者名稱和電子郵件使用簡單的標量值,請使用此
def configure_permitted_parameters
devise_parameter_sanitizer . permit ( :sign_in ) do | user_params |
user_params . permit ( :username , :email )
end
end
如果您有一些複選框表示使用者在註冊時可能扮演的角色,則瀏覽器會將這些選定的複選框作為數組發送。數組不是強參數允許的標量之一,因此我們需要以以下方式配置 Devise:
def configure_permitted_parameters
devise_parameter_sanitizer . permit ( :sign_up ) do | user_params |
user_params . permit ( { roles : [ ] } , :email , :password , :password_confirmation )
end
end
有關允許的標量列表以及如何在嵌套哈希和數組中聲明允許的鍵,請參閱
https://github.com/rails/strong_parameters#nested-parameters
如果您有多個 Devise 模型,您可能需要為每個模型設定不同的參數消毒器。在這種情況下,我們建議繼承Devise::ParameterSanitizer
並添加您自己的邏輯:
class User :: ParameterSanitizer < Devise :: ParameterSanitizer
def initialize ( * )
super
permit ( :sign_up , keys : [ :username , :email ] )
end
end
然後配置您的控制器以使用它:
class ApplicationController < ActionController :: Base
protected
def devise_parameter_sanitizer
if resource_class == User
User :: ParameterSanitizer . new ( User , :user , params )
else
super # Use the default one
end
end
end
上面的範例將使用者允許的參數覆寫為:username
和:email
。配置參數的非惰性方法是在自訂控制器中定義上面的 before 過濾器。我們在下面的某些部分詳細介紹瞭如何配置和自訂控制器。
我們建立 Devise 是為了幫助您快速開發使用身份驗證的應用程式。但是,當您需要自訂它時,我們不想妨礙您。
由於 Devise 是一個引擎,因此它的所有視圖都封裝在 gem 內。這些視圖將幫助您入門,但一段時間後您可能想要更改它們。如果是這種情況,您只需呼叫以下生成器,它會將所有視圖複製到您的應用程式:
rails generate devise:views
如果您的應用程式中有多個 Devise 模型(例如User
和Admin
),您會注意到 Devise 對所有模型使用相同的視圖。幸運的是,Devise 提供了一種簡單的方法來自訂視圖。您需要做的就是在config/initializers/devise.rb
檔案中設定config.scoped_views = true
。
執行此操作後,您將能夠根據users/sessions/new
和admins/sessions/new
等角色查看視圖。如果在範圍內找不到視圖,Devise 將使用devise/sessions/new
處的預設視圖。您也可以使用生成器產生範圍視圖:
rails generate devise:views users
如果您只想產生幾組視圖,例如registerable
和confirmable
模組的視圖,則可以使用-v
標誌將視圖清單傳遞給生成器。
rails generate devise:views -v registrations confirmations
如果視圖層級的自訂還不夠,您可以按照以下步驟自訂每個控制器:
使用需要範圍的生成器建立自訂控制器:
rails generate devise:controllers [scope]
如果您指定users
作為範圍,控制器將在app/controllers/users/
中建立。會話控制器將如下所示:
class Users :: SessionsController < Devise :: SessionsController
# GET /resource/sign_in
# def new
# super
# end
...
end
使用-c
標誌指定一個或多個控制器,例如: rails generate devise:controllers users -c sessions
告訴路由器要使用這個控制器:
devise_for :users , controllers : { sessions : 'users/sessions' }
建議但不要求:將視圖從devise/sessions
複製(或移動)到users/sessions
。如果您跳過此步驟,Rails 將因繼承而繼續使用devise/sessions
中的視圖,但讓視圖與控制器匹配可以保持一致。
最後,更改或擴展所需的控制器操作。
您可以完全覆蓋控制器操作:
class Users :: SessionsController < Devise :: SessionsController
def create
# custom sign-in code
end
end
或者您可以簡單地向其添加新行為:
class Users :: SessionsController < Devise :: SessionsController
def create
super do | resource |
BackgroundWorker . trigger ( resource )
end
end
end
這對於在某些操作期間觸發後台作業或記錄事件非常有用。
請記住,Devise 使用閃現訊息來讓用戶知道登入是否成功。 Devise 希望您的應用程式適當地呼叫flash[:notice]
和flash[:alert]
。不要列印整個閃存哈希,僅列印特定鍵。在某些情況下,Devise 會為 flash 雜湊添加一個:timedout
鍵,該鍵不用於顯示。如果您打算列印整個散列,請從散列中刪除此鍵。
Devise 也附帶預設路由。如果您需要自訂它們,您應該能夠透過 devise_for 方法來完成。它接受多個選項,如 :class_name、:path_prefix 等,包括更改 I18n 路徑名的可能性:
devise_for :users , path : 'auth' , path_names : { sign_in : 'login' , sign_out : 'logout' , password : 'secret' , confirmation : 'verification' , unlock : 'unblock' , registration : 'register' , sign_up : 'cmon_let_me_in' }
請務必查看devise_for
文件以了解詳細資訊。
如果您需要更深入的自訂,例如除了“/users/sign_in”之外還允許“/sign_in”,您所需要做的就是正常建立路由並將它們包裝在路由器中的devise_scope
區塊中:
devise_scope :user do
get 'sign_in' , to : 'devise/sessions#new'
end
這樣,您就可以告訴 Devise 在存取「/sign_in」時使用作用域:user
。請注意, devise_scope
也具有與路由器中as
別名。
請注意:您仍然需要在路由中新增devise_for
才能使用 helper 方法,例如current_user
。
devise_for :users , skip : :all
Devise 與 Hotwire/Turbo 集成,將此類請求視為導航,並配置某些錯誤回應和重定向以匹配預期行為。預設情況下,使用以下回應配置產生新應用程序,現有應用程式可以透過將配置新增至其 Devise 初始值設定項目來選擇加入:
Devise . setup do | config |
# ...
# When using Devise with Hotwire/Turbo, the http status for error responses
# and some redirects must match the following. The default in Devise for existing
# apps is `200 OK` and `302 Found` respectively, but new apps are generated with
# these new defaults that match Hotwire/Turbo behavior.
# Note: These might become the new default in future versions of Devise.
config . responder . error_status = :unprocessable_entity
config . responder . redirect_status = :see_other
end
重要提示:這些自訂回應要求responders
gem 版本為3.1.0
或更高版本,如果要使用此配置,請確保更新它。查看此升級指南以獲取更多資訊。
注意:上述狀態配置可能會成為未來版本中 Devise 的預設配置。
如果您要從 Rails-ujs 遷移,則可能需要在應用程式中進行一些其他變更才能與 Hotwire/Turbo 配合使用:
data-confirm
選項需要變更為data-turbo-confirm
,以便 Turbo 正確處理這些內容。data-method
選項需要變更為data-turbo-method
。這對於button_to
或form
來說並不是必需的,因為 Turbo 可以處理這些。如果您將 Devise 設定為透過:delete
註銷,並且使用連結(而不是表單中包含的按鈕)透過method: :delete
選項註銷,則需要按照上述方式更新它們。 (Devise 不在其共享視圖中提供註銷連結/按鈕。)
請務必檢查您的觀點,尋找這些觀點,並進行適當的更改。
Devise 將 Flash 訊息與 I18n 結合使用,並結合 Flash 鍵 :notice 和 :alert。要自訂您的應用程序,您可以設定區域設定檔:
en :
devise :
sessions :
signed_in : ' Signed in successfully. '
您也可以使用路由中給出的單數名稱根據您配置的資源建立不同的訊息:
en :
devise :
sessions :
user :
signed_in : ' Welcome user, you are signed in. '
admin :
signed_in : ' Hello admin! '
Devise 郵件程式使用類似的模式來建立主題訊息:
en :
devise :
mailer :
confirmation_instructions :
subject : ' Hello everybody! '
user_subject : ' Hello User! Please confirm your email '
reset_password_instructions :
subject : ' Reset instructions '
查看我們的區域設定檔以檢查所有可用的消息。您可能也對我們的 wiki 上提供的眾多翻譯之一感興趣:
https://github.com/heartcombo/devise/wiki/I18n
注意:設計控制器繼承自ApplicationController。如果您的應用程式使用多個區域設置,則應確保在 ApplicationController 中設定 I18n.locale。
Devise 包括一些用於控制器和整合測試的測試助手。為了使用它們,您需要在測試案例/規格中包含相應的模組。
控制器測試要求您在測試案例或其父ActionController::TestCase
超類別中包含Devise::Test::IntegrationHelpers
。對於 5 之前的 Rails 版本,請改為包含Devise::Test::ControllerHelpers
,因為控制器測試的超類已更改為 ActionDispatch::IntegrationTest(有關更多詳細信息,請參閱集成測試部分)。
class PostsControllerTest < ActionController :: TestCase
include Devise :: Test :: IntegrationHelpers # Rails >= 5
end
class PostsControllerTest < ActionController :: TestCase
include Devise :: Test :: ControllerHelpers # Rails < 5
end
如果您使用的是 RSpec,則可以將以下內容放入名為spec/support/devise.rb
檔案或spec/spec_helper.rb
中(如果您使用的是rspec-rails
,則將其放入spec/rails_helper.rb
中):
RSpec . configure do | config |
config . include Devise :: Test :: ControllerHelpers , type : :controller
config . include Devise :: Test :: ControllerHelpers , type : :view
end
只需確保此包含是在require 'rspec/rails'
指令之後進行的。
現在您可以在控制器測試中使用sign_in
和sign_out
方法:
sign_in @user
sign_in @user , scope : :admin
如果您正在測試 Devise 內部控制器或從 Devise 繼承的控制器,則需要在發出請求之前告訴 Devise 應使用哪個對應。這是必要的,因為 Devise 從路由器獲取此訊息,但由於控制器測試不通過路由器,因此需要明確說明。例如,如果您正在測試使用者範圍,只需使用:
test 'GET new' do
# Mimic the router behavior of setting the Devise scope through the env.
@request . env [ 'devise.mapping' ] = Devise . mappings [ :user ]
# Use the sign_in helper to sign in a fixture `User` record.
sign_in users ( :alice )
get :new
# assert something
end
透過包含Devise::Test::IntegrationHelpers
模組可以使用整合測試助手。
class PostsTests < ActionDispatch :: IntegrationTest
include Devise :: Test :: IntegrationHelpers
end
現在您可以在整合測試中使用下列sign_in
和sign_out
方法:
sign_in users ( :bob )
sign_in users ( :bob ) , scope : :admin
sign_out :user
RSpec 使用者可以在其:feature
規範中包含IntegrationHelpers
模組。
RSpec . configure do | config |
config . include Devise :: Test :: IntegrationHelpers , type : :feature
end
與控制器測試不同,整合測試不需要提供devise.mapping
env
值,因為可以透過測試中執行的路由來推斷映射。
您可以在 wiki 中閱讀有關使用 RSpec 測試 Rails 控制器的更多資訊:
Devise 提供開箱即用的 OmniAuth 支持,以便與其他提供者進行身份驗證。要使用它,只需在config/initializers/devise.rb
中指定您的 OmniAuth 配置:
config . omniauth :github , 'APP_ID' , 'APP_SECRET' , scope : 'user,public_repo'
您可以在 wiki 中閱讀有關 OmniAuth 支援的更多資訊:
Devise 允許您設定任意數量的 Devise 模型。如果您想要一個僅具有身份驗證和逾時功能的管理模型,除了上面的使用者模型之外,只需執行:
# Create a migration with the required fields
create_table :admins do | t |
t . string :email
t . string :encrypted_password
t . timestamps null : false
end
# Inside your Admin model
devise :database_authenticatable , :timeoutable
# Inside your routes
devise_for :admins
# Inside your protected controller
before_action :authenticate_admin!
# Inside your controllers and views
admin_signed_in?
current_admin
admin_session
或者,您可以簡單地運行 Devise 生成器。
請記住,這些模型將具有完全不同的路線。他們不會也不可能共用同一個控制器來進行登入、登出等操作。如果您希望不同的角色共享相同的操作,我們建議您使用基於角色的方法,透過提供角色列或使用專用的 gem 進行授權。
如果您使用 Active Job 透過佇列後端在背景傳遞 Action Mailer 訊息,則可以透過覆寫模型中的send_devise_notification
方法,透過現有佇列傳送 Devise 電子郵件。
def send_devise_notification ( notification , * args )
devise_mailer . send ( notification , self , * args ) . deliver_later
end
如果啟用可恢復模組,請注意,被盜的密碼重設令牌可能會讓攻擊者存取您的應用程式。 Devise 努力產生隨機、安全的令牌,並且僅將令牌摘要儲存在資料庫中,而不是純文字。然而,Rails 中的預設日誌記錄行為可能會導致純文字標記洩漏到日誌檔案中:
deliver_later
傳送密碼重設電子郵件,則密碼重設令牌將會外洩。預設情況下,Rails 將生產記錄器等級設定為 INFO。如果您希望防止令牌洩漏到日誌中,請考慮將生產記錄器等級變更為 WARN。在config/environments/production.rb
中:
config . log_level = :warn
Devise 支援 ActiveRecord(預設)和 Mongoid。要選擇另一個 ORM,只需在初始化程序檔案中需要它即可。
Rails 5+ 有一個內建的 API 模式,它會最佳化 Rails 以用作 API(僅)。 Devise在某種程度上能夠處理在此模式下建立的應用程序,而無需進行額外的修改,因為它不應該引發異常等。但在development
/ testing
過程中仍然可能會出現一些問題,因為我們仍然不知道這種相容性的全部範圍。 (有關更多信息,請參閱問題#4947)
僅 API 應用程式不支援透過 cookie 基於瀏覽器的身份驗證,這是設計的預設值。然而,在這些情況下,devise 仍然可以使用http_authenticatable
策略提供開箱即用的身份驗證,該策略使用 HTTP 基本驗證並在每個請求上對使用者進行身份驗證。 (有關詳細信息,請參閱此 wiki 文章“如何:使用 HTTP 基本身份驗證”)
HTTP 驗證的設計預設為停用狀態,因此需要在資料庫原則的設計初始值設定項目中啟用它:
config . http_authenticatable = [ :database ]
此限制不會限制您在應用程式中或透過基於 gem 的設計擴充來實現自訂 Warden 策略。 API 的常見身份驗證策略是基於令牌的身份驗證。有關擴展設備以支援此類身份驗證和其他身份驗證的更多信息,請參閱有關簡單令牌身份驗證範例和替代方案的 wiki 文章或有關使用 Devise 的自訂身份驗證方法的部落格文章。
API 模式會變更中間件堆疊的順序,這可能會導致Devise::Test::IntegrationHelpers
出現問題。當使用整合測試助手(例如#sign_in
)時,此問題通常表現為undefined method `[]=' for nil:NilClass
解決方案只是透過將以下內容新增至 test.rb 來重新排序中間件:
Rails . application