Devise Github Wiki 中文文档
README
commit信息:Remove Heroku anchor link and fix some typos | 提交者:ptcodes | 提交时间:2020-06-16 | 版本:b25492e
Devise是基于Warden的灵活的rails身份认证解决方案。 它:
- 基于Rack;
- 它是一个基于rails引擎的完整MVC解决方案;
- 可以同时登录多个模型;
- 基于模块化概念: 只使用你需要的部分。
它由10个模块组成:
- 数据库身份认证:哈希然后在数据库中储存密码,用来在用户登录时验证用户身份。身份验证中可以通过post请求或者HTTP基本验证来完成。
- Omniauthable: 添加OmniAuth (https://github.com/omniauth/omniauth) 支持。
- Confirmable: 发送带确认说明的电子邮件,并且在用户登录期间验证账号是否已经证实邮箱账号。
- Recoverable: 重设用户密码并且发送重设指令。
- Registerable: 通过注册程序来处理注册用户,也可以让用户编辑和删除他们的帐号。
- Rememberable: 管理token的生成和token的清理以便用储存的cookie记着用户。
- Trackable: 记录登录次数、时间戳和IP地址。
- Timeoutable: 使在特定时间段内没有活动的session变为过期session。
- Validatable:提供电子邮箱和密码验证。它是可配置也是可定制的,所以你可以定义自己的验证。
- Lockable:在一个特定数的登录失败之后锁定账户。可以通过发送电子邮件解锁或者在特定时间段后解锁。
目录
<!-- TOC depthFrom:1 depthTo:6 withLinks:1 orderedList:0 -->
资料
Devise wiki
divse WIki有许多关于Devise的附加资源,包括许多“how-to”文章以及常见问题回答。请在完成README之后浏览Wiki:
https://github.com/heartcombo/devise/wiki
Bug报告
如果你发现了Devise的问题,我们也想知道。但是,我们要求你在提交错误报告之前先阅读以下准则:
https://github.com/heartcombo/devise/wiki/Bug-reports
如果你发现了与安全相关的错误,请 不 要发起github issue。请给 heartcombo@googlegroups.com 发送电子邮件。
StackOverflow和邮件列表
如果你有任何问题、评价或是担忧,请使用stackoverflow而不是GitHub issue:
http://stackoverflow.com/questions/tagged/devise
你仍然可以阅读过时的邮件列表
https://groups.google.com/group/plataformatec-devise
RDocs
你可以在这里看Devise的RDoc格式文档:
http://rubydoc.info/github/heartcombo/devise/master/frames
如果你搭配以前版本的rails来使用devise, 在你安装了gem之后可以在命令行运行"gem server"命令来获取旧的文档。
例子应用
在GitHub上有一些有效的例子应用,它们搭配不同版本的Rails示范了许多devise功能。
扩展
我们的社区已经创建了许多扩展,添加了Devise没有的功能。你可以在这里查看有效扩展列表并且添加你自己的扩展:
https://github.com/heartcombo/devise/wiki/Extensions
贡献
我们希望你想给device做贡献。阅读这篇简短的概览来获取一些如何起步的资料。
https://github.com/heartcombo/devise/wiki/Contributing
如果你通常想给你的功能改变写一些测试。为了运行测试,请进入Devise的顶层水平文件夹,然后运行 bundle install
和 bin/test
。
Devise可以搭配许多Ruby和rails版本、ActiveRecord和Mongoid ORMs来工作,那意味着你可以搭配一些DEVISE_ORM
和 BUNDLE_GEMFILE
的修改来运行测试。
DEVISE_ORM
因为 Devise 同时支持 Mongoid 和 ActiveRecord, 所以我们依赖此变量用来运行每个ORM特定的代码。DEVISE_ORM
的默认值是active_record
。你可以传递mongoid
来运行Mongoid的测试:
DEVISE_ORM=mongoid bin/test
==> Devise.orm = :mongoid
在运行Mongoid测试时,需要在你的系统上有(2.0以上版)的MongoDB服务。
请注意,该命令的输出将显示正在使用的变量值。
BUNDLE_GEMFILE
我们可以使用该变量来告诉bundler它该使用哪个Gemfile文件(来替代当前文件夹下的Gemfile文件)。在[gemfiles]](https://github.com/heartcombo/devise/tree/master/gemfiles) 文件夹里,有我们支持的每个rails版本。当你给我们发送一个获取请求时, it may happen that the test suite breaks on Travis using some of them.如果出现这种状况,你可以使用BUNDLE_GEMFILE
变量来模拟相同的环境。
例如,如果在使用Ruby 2.4.2和Rails 4.1时测试代码出问题了,你可以像下面这样做:
rbenv shell 2.4.2 # or rvm use 2.4.2
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bin/test
如果测试代码在Mongoid中出错,你也可以一起使用它们:
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable 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起步?
如果你正在构建第一个Rails应用,我们建议你 不要 使用Devise。使用Devise依赖对rails框架的正确理解。在这种情况下,我们建议你从头建立一个简单的身份认证系统。这里有一些能帮你起步的资源:
- Michael Hartl's 的在线书籍: https://www.railstutorial.org/book/modeling_users
- Ryan Bates' Railscasts: http://railscasts.com/episodes/250-authentication-from-scratch and http://railscasts.com/episodes/250-authentication-from-scratch-revised
- Codecademy's Ruby on Rails: 身份认证和权限: https://www.codecademy.com/learn/rails-auth
如果你已经理解了rails和身份验证机制,我们向你保证Devise使用起来将非常合适。 :smiley:
起步
Devise 4.0工作在rails 4.1以上。把下面这行添加到你的Gemfile文件中:
gem 'devise'
然后运行bundle install
接下来你需要运行生成器:
$ rails generate devise:install
此时,许多操作说明将出现在console中。遵从这些操作说明,你需要在每个环境中设置Devise的邮件发送者默认URL选项。这里有一个config/environments/development.rb
文件的参考配置:
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
生成器将装上一个初始程序,它描述了所有的Devise配置选项。你 一定要 看一看。当你看过之后,你可以使用生成器把device添加到你的任何一个模型中。
你需要使用应用里用户的类名来重置下面命令中的MODEL
(它经常是User
也可以是Admin
)。该命令将创建模型(如果模型还不存在),并且配置它使用Devise的默认模块。生成器还将你的config/routes.rb
文件配置为指向Devise的控制器。
$ rails generate devise MODEL
接下来查看MODEL来添加你想添加的附加配置选项,像是confirmable和lockable。如果你添加了一个配置项,请你确保检查了该迁移文件(如果你的ORM支持,则由生成器创建)同时给适当的部分解除注释。例如你在模型中添加了confirmable选项,你需要在迁移文件中解除Confirmable部分的注释。
然后运行rails db:migrate
在改变的Devise的配置选项之后你应该重启你的应用(包括停止spring)。否则你将得到奇怪的错误,例如:用户不能登录和路由帮助方法未定义。
控制器过滤器和帮助方法
device将创建一些在你的控制器和视图里可以使用的帮助方法。为了设置控制器使用用户身份认证,只需要添加以下before_action(假设你的Devise模型是'User'):
before_action :authenticate_user!
对Rails 5来说,请注意,protect_from_forgery
不再预置到before_action
链中,因此,如果你在protect_from_forgery
之前设置authenticate_user
,你的请求将产生"Can't verify CSRF token authenticity"的结果。为了解决该问题,请改变你调用它们的顺序,或者使用protect_from_forgery prepend: true
。
如果你的Devise模型不是User,请使用"_yourmodel"重置"_user"。对下面的指令应用相同的逻辑。
使用下面的帮助方法来验证用户是否登录:
user_signed_in?
下面的帮助方法在当前有登录用户时有效:
current_user
你可以获取当前用户的session:
user_session
在登录用户、confirming the account或者更新密码之后,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已更改 :warning:
- 以前版本的Devise,请看 https://github.com/heartcombo/devise/tree/3-stable#strong-parameters *
在定制你的视图时,你或许想往一些form里添加新的属性。Rails 4 把参数安全处理操作从模型移动到了控制器,从而使Devise在控制器中也能处理此问题。
Devise中有三个action,它们可以传递给模型任何参数,因此它们需要被安全操作。它们的名字和默认允许的参数是:
sign_in
(Devise::SessionsController#create
) -只允许身份验证keys(像是email
)sign_up
(Devise::RegistrationsController#create
) - 允许身份验证keys加password
和password_confirmation
account_update
(Devise::RegistrationsController#update
) - 允许身份验证keys加password
,password_confirmation
和current_password
有时你想允许其它参数(the lazy way™),你可以在ApplicationController
中使用before action:
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
以上代码可以添加任何附加字段,这些字段是简单的scalar类型。如果你有一些嵌套属性(例如,你正在使用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允许完全改变它的默认行为或者通过传递一个块来调用定制的行为:
为了允许简单scalar值的username和email,请使用以下代码
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_in) do |user_params|
user_params.permit(:username, :email)
end
end
如果你有一些复选框,它们展示一些用户可以在注册过程中获取的角色,浏览器会使用数组来发送这些选定的复选框值。数组不是健壮参数功能允许的scalars中的一个类型,因此我们需要像下面这样配置Devise:
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) do |user_params|
user_params.permit({ roles: [] }, :email, :password, :password_confirmation)
end
end
想要列出允许的scalars,以及如何在嵌套hashes和arrays中声明允许的keys,请参阅
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
以上的例子重写user允许的参数为:username
和 :email
。该non-lazy配置参数方式将在定制控制器中定义以上before过滤器。我们在以下部分详细讲解如何配置和定制控制器。
配置视图
我们创建了Devise以帮你快速开发一个需要身份认证的应用。However, we don't want to be in your way when you need to customize it.
因为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
。如果在scope中没有发现任何视图,Devise将使用devise/sessions/new
文件中的默认视图。你也可以使用生成器来生成scoped视图:
$ rails generate devise:views users
如果你只想生成少数的视图,像是只有registerable
和 confirmable
模块的视图,你可以使用-v
标记来给生成器传递一个模块列表。
$ rails generate devise:views -v registrations confirmations
配置控制器
如果视图水平的定制不够你用,你可以遵从以下步骤来定制每个控制器:
使用依赖scope的生成器来创建和定制控制器:
$ rails generate devise:controllers [scope]
如果你指定
users
作为scope, 控制器会被创建在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
处。因为控制器已经被改变,它将不会使用devise/sessions
处的默认视图。然后修改和扩展你需要的控制器actions。
你可以完全重写一个控制器action:
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 hash中添加了:timedout
键,该键不用于显示。如果你想要打印整个hash请移除该键。
配置路由
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
通过该种方式,当"/sign_in"被请求时Devise会使用:user
域。注意,devise_scope
在路由器文件中也是别名就像as
一样。
请注意:为了使用像current_user
这样的帮助方法,你仍需要在你的路由文件中添加devise_for
。
devise_for :users, skip: :all
I18n
Devise搭配I18n来使用闪现消息,并且使用: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
注意事项:Devise控制器继承ApplicationController。如果你的应用使用多种本地化,你应该确保在ApplicationController中设置I18n.locale 。
测试帮助方法
Devise给控制器测试和集成测试提供了一些测试帮助方法。为了使用它们你应该分别包含它们到你的测试cases/specs中。
控制器测试
控制器测试依赖你在测试用例中包含Devise::Test::IntegrationHelpers
,或者是它的超类ActionController::TestCase
。对于Rails 5之前的版本,要包含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需要从路由中得到该信息,但是因为控制器测试不通过路由传递该信息,所以该信息需要被明确说明。例如,你正在测试用户scope,只需这样做:
test 'GET new' do
# 通过env设置Devise scope的模拟路由
@request.env['devise.mapping'] = Devise.mappings[:user]
# 使用sign_in帮助方法 来登录固件`User`。
sign_in users(:alice)
get :new
# 断言一些事情
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
specs中包含IntegrationHelpers
模块。
RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :feature
end
不像控制器测试,集成测试不需要给它提供devise.mapping
、env
值,因为使用你测试中执行的路由可以推断出该路径。
在该Wiki中你可以阅读更多关于Rails 3 - Rails 4的RSpec控制器测试:
OmniAuth
为了使用其它服务商的身份验证信息,Devise创建了开箱即用的OmniAuth支持。想要使用它,只需要在config/initializers/devise.rb
文件中指定你的OmniAuth配置:
config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
在该Wiki中你可以查阅更多关于OmniAuth支持的信息:
配置多个模型
Devise让你可以设置许多你想有的Devise模型。如果你想有一个Admin模型,只是用来提供身份验证和超时功能,并且有额外的User模型,只需运行:
# 创建依赖字段的迁移
create_table :admins do |t|
t.string :email
t.string :encrypted_password
t.timestamps null: false
end
# 在你的Admin模型文件中加入
devise :database_authenticatable, :timeoutable
# 在你的路由文件中加入
devise_for :admins
# 在你的保护控制器中加入
before_action :authenticate_admin!
# 在你的控制器和视图中加入
admin_signed_in?
current_admin
admin_session
或者,你只需运行Devise生成器。
请注意这些模型将有完全不同的路由。它们 不可以 也 不能 为了登录账户、退出账户等操作分享相同的控制器。在这种情况下,如果你想给不同的角色分享一些同样的动作,我们推荐你使用基于角色的方法,提供一个角色列,或者用专业的权限gem进行授权。
ActiveJob集成
如果你使用Rails 4.2 和 ActiveJob通过后台队列来投递ActionMailer信息,在你的模型中复写send_devise_notification
方法,这样你可以使用队列来发送Devise电子邮件。
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
重设密码token和rails日志记录
如果你开启了Recoverable模块,注意一个密码重设token被盗可以让攻击者登陆你的应用。Devise尽力生成随机的、安全的tokens,并且在数据库中储存token摘要,不储存纯文本。Rails中的默认日志记录行为会把纯文本token泄漏到日志文件中:
- 对于DEBUG日志记录水平,Action Mailer日志会记录完整的发送的电子邮件内容。在电子邮件中投递给用户的密码重设token将会被泄露。
- 在INFO水平下Active Job会记录传给每一个排队作业的所有参数。如果你配置Devise在发送密码重设电子邮件时使用
deliver_later
,密码重设tokens将会被泄露。
Rails 默认把生产日志记录水平设为DEBUG。 如果你希望阻止tokens 被泄露到你的日志文件中,请考虑把你的生产日志水平设为WARN 。在config/environments/production.rb
文件中:
config.log_level = :warn
其它的ORMs
Devise (默认)支持ActiveRecord和Mongoid。对于选择其它ORM的情况,只需在初始化文件中请求它。
Rails API模式
Rails 5+内置了API 模式,它优化Rails (只)使用API。从某种意义上讲,Devise能够处理以这种方式构建的应用程序,而无需进行其它修改,它不应该引发异常。但是一些issues依然在development
/testing
环境下被触发,我们仍然不太了解整体的兼容性程度。(了解详情,请查看issue #4947)
支持认证策略
API-only应用不支持使用cookie的浏览器模式认证,那是devise的默认方式。但是,在这种情况下,devise仍提供开箱即用的http_authenticatable
策略身份认证,该身份认证使用HTTP Basic Auth并在每个请求上验证用户。(了解详情,请查看该Wiki文章How To: Use HTTP Basic Authentication)
devise默认关闭HTTP Auth,因此如果使用它,需要在初始化文件中开启数据库策略:
config.http_authenticatable = [:database]
该约束不限制在你的应用里和在devise的gem-based扩展里实现定制的warden 策略。
token-based身份认证是一个公认的API应用身份认证策略。关于扩展devise支持该种身份认证和其他的身份认证的更多信息,请查看这篇Wiki文章简单Token身份认证例子和替代方案,或者该篇关于定制Devise身份验证方法的博客
测试中
API模式改变了中间件栈的顺序,所以会造成Devise::Test::IntegrationHelpers
问题。该问题通常在使用集成测试帮助方法时显现为undefined method `[]=' for nil:NilClass
错误,例如#sign_in
。解决方法很简单,添加下面的代码到测试文件中来重新排列中间件:
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore
关于该问题的深层次理解,请回顾该issue 。
另外需要注意的是,离开了视图支持,此时,那些来自于Confirmable, Recoverable 和 Lockable的邮件流不能被直接支持。
附加资料
Warden
Devise基于Warden,它是一个被Daniel Neighman创建的通用身份验证框架。我们鼓励你在下面地址里阅读更多的Warden信息:
https://github.com/wardencommunity/warden
贡献者们
我们有一长串有价值的贡献者。在这里查看他们:
https://github.com/heartcombo/devise/graphs/contributors
授权
MIT License. Copyright 2020 Rafael França, Leonardo Tegon, Carlos Antônio da Silva. Copyright 2009-2019 Plataformatec.
Devise logo的许可证是Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.