I’m using Rails 8 with Devise for authentication and have encountered an issue with OAuth (Google, GitHub) sign-in behavior. Here’s the observed behavior:
Good Working Scenario: Email Sign-In
- When a user clicks a link (e.g.,
/blogs
) that requires authentication, they are redirected to the login page. - The user enters their email and password. If the credentials are valid, they are redirected to the
/blogs
page. - If the user presses the browser’s back button while on the
/blogs
page, the app redirects the user to the home page and correctly displays the flash message: "You are already signed in".
Problematic Scenario: OAuth (Google) Sign-In
- When a user clicks a link (e.g.,
/blogs
) that requires authentication, they are redirected to the login page. - The user clicks the "Sign in with Google" button, completes the OAuth process, and is redirected to the
/blogs
page. - If the user presses the browser’s back button while on the
/blogs
page:- The login page reappears instead of redirecting them to the home page and displaying the flash message: "You are already signed in."
- If the user clicks the "Sign in with Google" button again, it raises an
ActionController::InvalidAuthenticityToken
error.
Question
How can I handle OAuth sign-in in Rails 8 with Devise so that, if the user is already signed in via OAuth, the app redirects to the home page with a flash message ("You are already signed in") when the user navigates back to the login page (e.g., by clicking the back button), without needing to refresh the page?
Additional Context
Here's my OmniauthCallbacksController
:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def github
handle_auth("GitHub")
end
def google_oauth2
handle_auth("Google")
end
def handle_auth(kind)
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: kind) if is_navigational_format?
else
session["devise.#{kind.downcase}_data"] = request.env["omniauth.auth"].except(:extra)
redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
end
end
end
the user.rb
:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :trackable, :omniauthable, omniauth_providers: [ :github, :google_oauth2 ]
# handle OmniAuth callbacks
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20] # Generate a random password
user.first_name = auth.info.first_name || auth.info.name
user.last_name = auth.info.last_name
# Bypass confirmation by setting `confirmed_at` to the current time
user.confirmed_at = Time.current
end
end
end
and the button for the Google sign in:
= button_to user_google_oauth2_omniauth_authorize_path,
class: "btn btn-social w-100",
"data-turbo" => false do
%span.icon-holder
= image_tag("social/google-logo.svg")
%span.btn-text Sign in with Google
I’ve already tried the following approaches:
- Overriding the
SessionsController#new
Method: I tried overridingDevise::SessionsController#new
to redirect already-signed-in users from the login page, but it didn’t resolve the behavior with OAuth.
class Users::SessionsController < Devise::SessionsController
def new
if user_signed_in?
redirect_to root_path, notice: "You are already signed in." and return
end
super
end
end
- Adding Cache-Control Headers: I added
Cache-Control
headers to prevent the browser from caching the login page, but it didn’t fix the issue.
class ApplicationController < ActionController::Base
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern
before_action :authenticate_user!
before_action :set_no_cache_headers, if: :devise_controller?
protected
def set_no_cache_headers
response.headers["Cache-Control"] = "no-cache, no-store"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
end
end
Currently, I’ve worked around the issue by adding Cache-Control
headers to the root page. While this solution works, I’m hoping there’s a better approach.
class HomeController < ApplicationController
before_action :set_no_cache_headers, only: [ :index ]
skip_before_action :authenticate_user!
def index
@categories = Category.all
# popular topics
@topics = Topic.order(id: :desc).limit(8)
end
end
Any insights or solutions would be greatly appreciated!
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745564729a4633323.html
评论列表(0条)