这两天学习了下CanCan的作用,顺便把验证用户登入的功能学习了。rails下有功能强大的Devise,不过有时候使用简单的方法就能达到预期的效果。
本文使用admin的登入作为例子讲解
涉及到的文件: admin_session_helper.rb , admin_sessions_controller.rb 两个文件总结的内容都写在注释上了,请认真
首先分析admin_sessions_controller.rb文件,代码如下:
module Admin
class AdminSessionsController < Admin::ApplicationController
skip_authorization_check #跳过权限验证
skip_filter :authenticate_admin! #跳过登入验证,要不就无法执行下面的代码
def new
@admin = Admin.new #新增Admin对象,但在create中没有@admin.save这样的操作,所以不会有admin被存入数据库,
#create的作用只是从浏览器获取输入的 name,和 password。即:获取params[:name],params[:password]
end
def create
admin = Admin.find_by(name: params[:admin][:name])
if admin.blank? || params[:admin][:name].blank? #对浏览器从输入框获取到的name,和password进行判断。通过name找到数据库中的相应记录
return render js: " $('#js-admin-sign-in-validate').html('* 管理员不存在');" #先在数据库中查找是否有这个输入的name
elsif params[:admin][:password].blank?
return render js: " $('#js-admin-sign-in-validate').html('* 密码不能为空');"
elsif admin.password != params[:admin][:password] #password 不是admin的字段,而是在model中的方法,最下面会贴出原因
return render js: " $('#js-admin-sign-in-validate').html('* 密码错误');" #进一步判断密码是否为空,密码是否和数据库中相对应
end
admin_sign_in(admin.id, params[:remember_me].present?) #如果通过了上面的账户和密码的判断,则把这个admin的id传到
return render js: " window.location.href='#{admin_root_path}';" #admin_sign_in 方法中,以及浏览器传来的remember_me。此时,admin_sign_in 方法为true
end
#然后请查看admin_session_helper.rb文件内容
def destroy #退出登入操作 其实是admin_session_helper.rb 中的admin_sign_out起作用
admin_sign_out
redirect_to admin_root_path
end
end
private
def admin_params
params.require(:admin).permit(:password)
end
end
end
文件代码: admin_session_helper.rb #这个helper文件的作用总结为:1.三个方法:登入,登出,和用于判断已登入的方法
module Admin # 2.将登入用户的id,存入cookies Hash中保存。
module AdminSessionHelper # 是 cookies.signed[]临时保存,关闭网页后就不保存登入信息,
#还是cookies.permanent.signed[]长久保存,关闭网页回来后还有登入信息
def session_key_admin_id
" ss_key" #定义一个Hash的key,只是起到名字的意义
end
def current_admin_id
@current_admin_id ||= cookies.signed[session_key_admin_id] #当前登入admin对象id 方法,便于后面程序的直接调用
end
def current_admin #当前登入admin对象 方法,便于后面程序中的直接调用
@current_admin ||= Admin.find_by(id: current_admin_id)
end
def admin_sign_in(admin_id, remember_me = false) #应该先看这个方法,再看其他方法。这里就是admin.id传了进来,存到了cookies Hash中
if remember_me #remember_me 用于看是否长久保存登入信息
cookies.permanent.signed[session_key_admin_id] = admin_id
else
cookies.signed[session_key_admin_id] = admin_id
end
end
def admin_sign_out # 登出操作方法,即在cookies Hash 中使用delete方法删除相应的key,value也就被一起删除了
return unless admin_signed_in? #如果admin_signed_in? 这个方法不为真,说明没登入直接返回即可
cookies.delete session_key_admin_id # 删除id操作,cookies中就没有登入的id了,这样就退出了
end
def admin_signed_in?
current_admin_id.present? # id能够传过来存到cookies Hash中存在就是已登入,不存在就是退出
end
def authenticate_admin! #该方法用于加入到需要判断是否登入的页面对应的controller中,
unless admin_signed_in? #before_action :authenticate_admin! 这里起到验证是否登入,为true,说明id存到cookies Hash中了,登入 成功。为false,则登入失败
return redirect_to new_admin_admin_session_path
end
end
end
end
password 方法代码 写在了admin.rb文件中
include BCrypt #使用了BCrypt 起到加密作用的gem
def password
@password ||= Password.new(encrypted_password)
end
def password=(new_password)
@password = Password.create(new_password)
self.encrypted_password = @password
end
@password ||= Password.new(encrypted_password)
end
def password=(new_password)
@password = Password.create(new_password)
self.encrypted_password = @password
end
原理总结: controller中对比页面输入的账户和密码和数据库中的账户密码是否匹配,匹配则把该用户的id存入到cookies中保存。
cookies中一直有这个id,则一直是登入状态,一旦用户退出,cookies则会删除这个id,则用户处于退出状态
下一次登入则再循环上述过程