众所周知,网站开发中实现登入登出功能需要借助session技术,本篇文章希望使用Rails提倡的restful的风格,通过建立session的mvc来实现网站的登入登出。
ActiveModel::SecurePassword是Rails提供的安全密码API,这个API要求你有一个password_digest
的attribute,并提供以下验证机制:
首先将bcrypt加入到Gemfile中使用has_secure_password:
gem 'bcrypt', '~> 3.1.7'
下面给出在User的Model中的代码示例:
# Schema: User(name:string, password_digest:string)
class User < ActiveRecord::Base
has_secure_password
end
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save # => true
user.authenticate('notright') # => false
user.authenticate('mUc3m00RsqyRe') # => user
User.find_by(name: 'david').try(:authenticate, 'notright') # => false
User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
在上例中,使用authenticate方法就可以完成对用户密码的验证。
为User Model来设置validate条件,使用上一节Rails提供的API来实现User的验证。
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
end
# sessions_controller.rb
def new
if user_signed_in?
redirect_to root_url and return
end
end
def create
if user = User.find_by_email(params[:email])
if User.authenticate(params[:password]) # auth password
session[:user_id] = user.id
back_uri = if params[:back_to].present? # set back_to uri
params[:back_to]
else
root_url
end
redirect_to back_uri
else
flash[:error] = _("error_messages.incorrect_credentials")
render action: :new
end
else
flash[:error] = _("error_messages.not_exist")
redirect_to login_url
end
end
def destroy
session.delete(:user_id)
redirect_to login_url
end
# sessions/new.haml
%body
%h2 登入
= form_tag "login", method: :post do
.form-group
= label_tag :email, _('useremail')
= email_field_tag :email, params[:email], class: "form-control"
.form-group
= label_tag :password, _("password")
= password_field_tag :password, (params[:password] || nil), class: "form-control"
.form-group
= hidden_field_tag :back_to, params[:back_to]
= submit_tag _("title"), cta_params
在此我们指定路由:
get "login" => "sessions#new"
post "login" => "sessions#create"
delete "logout" => "sessions#destroy"
若使用Rails restful的做法,可以使用:
resources :sessions, only: [:new, :create, :destroy]