feat: add user authentication and authorization

- Implement friendly forwarding for user login
- Add correct_user method to ensure users can only edit their own profiles
- Update sessions_controller to handle forwarding URL
- Enhance user controller tests to verify redirection for unauthorized access

These changes improve user experience by allowing users to be redirected
back to their intended page after logging in. Additionally, the new
correct_user method enhances security by preventing users from editing
other users' profiles, ensuring proper authorization checks are in place.
This commit is contained in:
songtianlun 2025-01-03 13:48:59 +08:00
parent 23992ec4b2
commit 2b03661431
5 changed files with 50 additions and 4 deletions

View File

@ -7,10 +7,11 @@ class SessionsController < ApplicationController
user = User.find_by(email: params[:session][:email].downcase) user = User.find_by(email: params[:session][:email].downcase)
# if user && user.authenticate(params[:session][:password]) # if user && user.authenticate(params[:session][:password])
if user&.authenticate(params[:session][:password]) if user&.authenticate(params[:session][:password])
forwarding_url = session[:forwarding_url]
reset_session reset_session
params[:session][:remember_me] == '1' ? remember(user) : forget(user) params[:session][:remember_me] == '1' ? remember(user) : forget(user)
log_in user log_in user
redirect_to user redirect_to forwarding_url || user
else else
flash.now[:danger] = 'Invalid email/password combination' flash.now[:danger] = 'Invalid email/password combination'
render 'new' render 'new'

View File

@ -1,6 +1,7 @@
class UsersController < ApplicationController class UsersController < ApplicationController
include SessionsHelper include SessionsHelper
before_action :logged_in_user, only: [:edit, :update] before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show def show
@user = User.find(params[:id]) @user = User.find(params[:id])
# debugger # debugger
@ -47,8 +48,14 @@ class UsersController < ApplicationController
def logged_in_user def logged_in_user
unless logged_in? unless logged_in?
store_location
flash[:danger] = "Please log in." flash[:danger] = "Please log in."
redirect_to login_url redirect_to login_url
end end
end end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end end

View File

@ -41,4 +41,12 @@ module SessionsHelper
reset_session reset_session
@current_user = nil @current_user = nil
end end
def current_user?(user)
user && user == current_user
end
def store_location
session[:forwarding_url] = request.original_url if request.get?
end
end end

View File

@ -1,6 +1,10 @@
require "test_helper" require "test_helper"
class UsersControllerTest < ActionDispatch::IntegrationTest class UsersControllerTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
@other_user = users(:archer)
end
test "should get new" do test "should get new" do
get signup_path get signup_path
assert_response :success assert_response :success
@ -11,4 +15,19 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
assert_response :success assert_response :success
assert_select "title", full_title("Sign up") assert_select "title", full_title("Sign up")
end end
test "should redirect edit when logged in as wrong user" do
log_in_as(@other_user)
get edit_user_path(@user)
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect update when logged in as wrong user" do
log_in_as(@other_user)
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
assert flash.empty?
assert_redirected_to root_url
end
end end

View File

@ -5,9 +5,20 @@ class UsersEditTest < ActionDispatch::IntegrationTest
@user = users(:michael) @user = users(:michael)
end end
test "successful edit" do test "friendly forwarding just in first login" do
log_in_as(@user)
get edit_user_path(@user) get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
delete logout_path
assert_redirected_to root_url
log_in_as(@user)
assert_redirected_to user_url(@user)
end
test "successful edit with friendly forwarding" do
get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
assert_template 'users/edit' assert_template 'users/edit'
name = "Foo Bae" name = "Foo Bae"
email = "foo@bar.com" email = "foo@bar.com"