1、功能描述
(1)登录需要填写信息:邮箱、密码。当邮箱没有注册需要进行相应的提示。
(2)将数据库保存的密码解密后,与用户在页面输入的密码作对比,相同可登录。
(3)用户角色为管理员时,需要判断这个账号的状态,状态为未激活时(status为1),需要flash.notice提醒激活。
2、编辑controller、view、路由
(1)在路由文件config/routes.rb中添加路由,通过此链接来提交在登录页面提交的信息
(2)编辑views/accounts/login.html.erb文件,将form_tag后面的链接改成/create_login
(3)在accounts_controller.rb中添加create_login方法
3、获取页面提交的数据,实现登录功能
(1)rails s启动项目,在浏览器中打开注册页面http://localhost:3000/login(注意mac电脑是http://192.168.33.10:3000/login)随便填写信息,点击登录按钮,回到终端,能看到终端返回的日志中包含以下params数据。
Parameters: {"utf8"=>"✓", "email"=>"猫宁", "password"=>"[FILTERED]", "commit"=>"登录"}
因为我们在root文件中指定了post 'create_login' => 'accounts#create_login'
,所以数据提交到链接/create_login时,会用我们在accounts_controller中的create_login方法来获取并处理。
params是一个哈希,里面有4个key分别为utf8、email、password、commit,在create_login方法中取出email的值应该像下面这样:
在注册时取email的值是email = params[:account][:email]
,因为from_tag和form_for的区别。可以回头复习一下,我们在3.4章中讲过。
(2)回到sublime,编辑我们刚刚在accounts_controller.rb中添加的create_login方法,实现登录功能
代码解析:
-
redirect_to :root
:root指的是在路由文件中root路由root 'home#index'
, 登录成功后,页面自动跳转到网站主页面
4、用session保存已登录的用户id,在没有关闭浏览器的情况下,一直保持登录状态
(1)编辑create_login方法,加入session,session是Rails中原本就有的方法,可以直接拿来用。
在flash.notice = "登录成功!"
代码的上面添加一行代码。
!!!注意在create_login方法中有两处这样的代码,都要加上
(2)在application_controller.rb文件,添加check_login方法,该方法用来检查当前是否有用户登录。
这个方法几乎在每个页面都需要加载,所以我们写在application_controller.rb里面
代码解析:
-
@current_user ||= session[:account_id] && Account.find(session[:account_id])
代码意思为:如果@current_user不为空,直接返回@current_user。如果@current_user为空,则查看session中的account_id值是否存在,如果存在则查找session中的account_id对应的用户信息并返回。如果没有登录则返回空。
相当于下面的代码:
||=符号的含义:
a ||= “hello” 当a为nil时,a的值为"hello";当a不为nil,返回a本身的值。
- a ||= 3
返回值为a = 3- b = 2
b ||= 3
b已经被赋值,返回值为2
(3)在home_controller.rb文件中添加下面一行代码
代码解析:
-
before_action :check_login, only:[:index]
代码意思为:在每次执行index方法之前,都要先执行application_controller.rb中的check_login方法,检查目前是否有用户登录。 -
before_action :check_login
去掉only限制,意思为:在home_controller中的每个action方法执行之前,都要先执行check_login方法
(4)在accouns_controller.rb中添加下面一行代码
代码解析:
在accouns_controller.rb中所有的action方法中,除了signup、create_account、login、create_login、logout方法。其他action执行前都要先执行application_controller.rb中的check_login方法,检查目前是否有用户登录。
(5)rails s启动项目,打开登录页面,登录上一节注册的账号,测试是否保存了session。我们测试主要是帮助大家更加深入了解一下session。
登录成功后,在主页面任意位置点击右键—检查(Windows系统按F12键)—Application—Cookies里面有一个session
说明session已经保存成功了。这是Chrome浏览器的检查方法。
5、主页面右上角显示
登录成功后,页面头部右测应该显示用户名称等信息,左侧根据用户角色的不同显示相应的信息,而不是登录注册链接
在views/layouts/application.html.erb文件中,修改下面信息:
现在用不同角色的账号登录后,主页面会显示当前用户信息以及对应的功能信息了
6、退出登录,注销session
(1)routes.rb中加上
delete、post、get有什么区别呢?
get,post,put,delete是与服务器交互的4种方法,对应着查,改,增,删4个操作。
get一般用于获取数据的,post一般用于更新数据。对资源的增,删,改,查操作,其实都可以通过get、post完成,不需要用到put和delete。
其实这4种交互方法的使用没有强制要求,但是我们尽量按照规范来。
(2)accounts_controller.rb中加上相应action方法
点击退出链接,通过/logout链接执行logout方法,将session[:account_id]的值置为nil,并且重定向到主页面。
(3)修改views/layouts/application.html.erb,加上/logout链接
7、将session换成cookie来持久化登录
(1)session和cookie的区别
- session以文件的形式存储在web服务器上,适合存储临时数据。cookie以文件的形式存储到计算机本地,存储数据时间长
- 如果网站关闭或者关机重启了,session数据可能会丢失,但是cookie数据不会出现这种问题
- cookie数据存储在本地,数据容易被伪造,安全性不高
(2)修改login.html.erb页面,添加「记住账号」勾选框,粘贴下面四行代码到文件中
(3)因为cookie数据存储在本地,如果直接存储account_id数据很容易被伪造,所以我们给用户生成属于这个用户唯一的16位随机数,来替代account_id代表这个用户。
A、需要再account表中添加一个新的字段来保存这个16位随机数,我们给这个字段取名为auth_token,在项目命令行下执行下面代码:
B、在app/models/account.rb文件中添加以下代码
添加的generate_token方法中,代码的意思为,先将auth_token字符置为nil,再运行auth_token = SecureRandom.urlsafe_base64
方法生成16位随机数,再通过while Account.exists?(auth_token:"#{auth_token}")
条件来判断目前已保存的Account数据中是否存在刚刚生成的16位随机数据,如果存在则重新生成,直到不存在为止,虽然概率非常小,但我们需要保证auth_token的唯一性。最后将唯一的auth_token值保存到数据库中。
代码解析:
-
begin
代码..
end while 条件
是一种while循环格式,先执行代码,再看条件是否为true,为true就继续循环执行代码,为false就停止循环。至少会执行一次代码 - before_create :generate_token
代码意思是,在account创建之前,先执行generate_token方法(刚刚在account.rb文件中创建的方法),也就是在account.save
操作之前,会先调用generate_token方法,然后再进行保存操作 -
Rails.logger.info "===auth_token==========#{auth_token}"
一般在测试里面使用,将你想要展示的内容打印到日志里面,我们这行打印生成的auth_token,来确认auth_token成功生成了。 -
auth_token = SecureRandom.urlsafe_base64
Rails中生成16位随机数的一个方法,可以直接调用来生成16位随机数
C、处理老数据
我们之前创建的用户,auth_token字段都是空的,我们需要处理一下
这样老数据也有auth_token字段啦
(4)将session有关的代码调整为cookies相关的代码
A、accounts_controller.rb中调整create_login方法,注意需要修改两处
代码解析:
-
cookies.permanent[:auth_token]
勾选remember_me,permanent方法会使cookie的到期时间是20年 -
cookies[:auth_token]
不勾选remember_me,cookie的到期时间是1小时
B、accounts_controller.rb文件中调整logout方法
C、application_controller.rb文件中调整check_login方法
D、测试
勾选remember_me登录,右键检查—Application下面有一个auth_token的cookie,到期时间是2038年,说明成功了