Rails-session
2020-11-03 本文已影响0人
littleyu
路由
- 在
config/routes
里添加resources :sessions, only: [:create, :destroy]
只需要这两个 API
Modal
- 手动创建
app/modal/session.rb
,因为 session 并不需要存在数据库中,内容
class Session
include ActiveModel::Model // 不能像 user 那样继承 ActiveRecord,但是我们又需要用到 Rails 提供的 class 里面的便利方法,所以这里需要引入模块 ActiveModel
attr_accessor :email, :password
validates_presence_of :email, :password
validates_format_of :email, with: /.+@.+/, if: :email
validates_length_of :password, minimum: 6, on: [:create], if: :password
end
Controller
- 使用命令创建 controller ,
bin/rails g controller sessions
,追加两个方法
class SessionsController < ApplicationController
def create
session = Session.new create_params
session.validate
render_resource session
end
def destroy
end
def create_params
params.permit(:email, :password)
end
end
追加一个自定义的验证,验证邮箱是否存在
class Session
include ActiveModel::Model
attr_accessor :email, :password, :user
validates_presence_of :email, :password
validate :check_email_present, if: :email
validates_format_of :email, with: /.+@.+/, if: :email
validates_length_of :password, minimum: 6, if: :password
validate :check_email_password_match, if: Proc.new {|s| s.email.present? and s.password.present?}
def check_email_present
user ||= User.find_by_email email
if user.nil?
errors.add :email, :not_present
end
end
def check_email_password_match
user ||= User.find_by_email email
if user and not user.authenticate(password)
errors.add :password, :not_match
end
end
end
attr_accessor :xxx 做了啥
- @xxx
- def xxx 获取 @xxx 的值
- def xxx= 赋值给 @xxx
为了避免出错,完善一下上面的代码
class Session
include ActiveModel::Model
attr_accessor :email, :password, :user
validates_presence_of :email, :password
validate :check_email_present, if: :email
validates_format_of :email, with: /.+@.+/, if: :email
validates_length_of :password, minimum: 6, if: :password
validate :check_email_password_match, if: Proc.new {|s| s.email.present? and s.password.present?}
def check_email_present
@user ||= User.find_by_email email
if @user.nil?
errors.add :email, :not_present
end
end
def check_email_password_match
@user ||= User.find_by_email email
if @user and not @user.authenticate(password)
errors.add :password, :not_match
end
end
end
增加 session 中间件
config/application.rb
https://edgeguides.rubyonrails.org/api_app.html
config.session_store :cookie_store, key: '_monery_session_id'
config.middleware.use ActionDispatch::Cookies
config.middleware.use config.session_store, config.session_options
增加 session
def create
s = Session.new create_params
s.validate
render_resource s
session[:current_user_id] = s.user.id
end
再给 user 增加一个根据 session_id 获取当前用户的路由
config/routes
get '/current_user_info', to: 'user#current_user_info'
app/controllers/users_controller.rb
def current_user_info
@user_id = session[:current_user_id]
@user = User.find_by_id @user_id
render_resource @user
end
记住密码
切记不可把用户密码直接存在 localStorage
Rails 官方没有提供最佳实践
因为做法各不相同
思路:
- 当用户记住密码时,带上相关字段发给服务器
- 服务器接受以后,下发一个随机数(r)并存在数据库和 session
- 当过了一段时间,session 过期以后,只剩下 r 被带上发送给服务器
- 服务器检查 r 是否有效且正确(比如记住密码7天有效),有效中就直接派发一个新的 session,
- 而数据库需要在 user 表中多增加两个字段 login_token 和 login_token_expired_at 即可
- 但是如果需要做多个设备的记住密码,上面方案就不够用了,因为新设备登陆,会覆盖数据库,所以我们就需要新增一张 user 的关联表,用来记录多个 login_token

三句话实现注销功能
config/routes,由于 Rails 定义的 destory 方法需要传一个 id,所以我们需要重新定义一个方法
delete 'sessions', to: 'sessions#destroy'
def destroy
session[:current_user_id] = nil
head 200
end