From ccd6b02a98451d746c2f9aa0f05354616f58c7dc Mon Sep 17 00:00:00 2001 From: songtianlun Date: Thu, 2 Jan 2025 16:47:26 +0800 Subject: [PATCH] feat: add remember me functionality for user sessions - Implement remember method in User model to generate and store a remember token - Update SessionsController to call remember on successful login - Enhance current_user method to retrieve user from cookies if session is not present - Add forget method to clear remember token on logout - Create migration to add remember_digest column to users table --- app/controllers/sessions_controller.rb | 1 + app/helpers/sessions_helper.rb | 24 +++++++++++++-- app/models/user.rb | 30 +++++++++++++++++++ app/views/layouts/application.html.erb | 1 + ...0102072521_add_remember_digest_to_users.rb | 5 ++++ db/schema.rb | 3 +- 6 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20250102072521_add_remember_digest_to_users.rb diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index d7101f6..78d1c52 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -8,6 +8,7 @@ class SessionsController < ApplicationController # if user && user.authenticate(params[:session][:password]) if user&.authenticate(params[:session][:password]) reset_session + remember user log_in user redirect_to user else diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb index 6deb590..b7cf36c 100644 --- a/app/helpers/sessions_helper.rb +++ b/app/helpers/sessions_helper.rb @@ -3,9 +3,21 @@ module SessionsHelper session[:user_id] = user.id end + def remember(user) + user.remember + cookies.permanent.encrypted[:user_id] = user.id + cookies.permanent[:remember_token] = user.remember_token + end + def current_user - if session[:user_id] - @current_user ||= User.find_by(id: session[:user_id]) + if (user_id = session[:user_id]) + @current_user ||= User.find_by(id: user_id) + elsif (user_id = cookies.encrypted[:user_id]) + user = User.find_by(id: user_id) + if user && user.authenticated?(cookies[:remember_token]) + log_in user + @current_user = user + end end end @@ -13,9 +25,15 @@ module SessionsHelper !current_user.nil? end + def forget(user) + user.forget + cookies.delete(:user_id) + cookies.delete(:remember_token) + end + def log_out + forget(current_user) reset_session @current_user = nil end - end diff --git a/app/models/user.rb b/app/models/user.rb index 483ea4a..cecb0dd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,5 @@ class User < ApplicationRecord + attr_accessor :remember_token # before_save { self.email = email.downcase } before_save { email.downcase! } validates :name, presence: true, length: { maximum: 50 } @@ -14,4 +15,33 @@ class User < ApplicationRecord BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end + + def User.new_token + SecureRandom.urlsafe_base64 + end + + def remember + self.remember_token = User.new_token + update_attribute(:remember_digest, User.digest(remember_token)) + end + + class << self + def digest(string) + cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : + BCrypt::Engine.cost + BCrypt::Password.create(string, cost: cost) + end + + def new_token + SecureRandom.urlsafe_base64 + end + end + + def authenticated?(remember_token) + BCrypt::Password.new(remember_digest).is_password?(remember_token) + end + + def forget + update_attribute(:remember_digest, nil) + end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index cb539e1..84a11be 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -20,6 +20,7 @@ <%= render 'layouts/footer' %> <%#= debug(params) if Rails.env.development? %> <%= debug(params.to_yaml) if Rails.env.development? %> + <%= debug(session) if Rails.env.development? %> <%= debug(Time.now) if Rails.env.development? %> diff --git a/db/migrate/20250102072521_add_remember_digest_to_users.rb b/db/migrate/20250102072521_add_remember_digest_to_users.rb new file mode 100644 index 0000000..7a46444 --- /dev/null +++ b/db/migrate/20250102072521_add_remember_digest_to_users.rb @@ -0,0 +1,5 @@ +class AddRememberDigestToUsers < ActiveRecord::Migration[8.0] + def change + add_column :users, :remember_digest, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 94fd020..ee50448 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,13 +10,14 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2024_12_31_060757) do +ActiveRecord::Schema[8.0].define(version: 2025_01_02_072521) do create_table "users", force: :cascade do |t| t.string "name" t.string "email" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "password_digest" + t.string "remember_digest" t.index ["email"], name: "index_users_on_email", unique: true end end