mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-07 17:36:22 +08:00
Since the introduction of dedicated login and signup pages (as opposed to modals), we've been seeing reports of issues where visitors aren't redirected back to the "page" they were at when they initiated the _authentication_ process. Since we have a bazillion of ways a user might authenticate (credentials, social logins, SSO, passkeys, discourse connect, etc...), it's really hard to know what a change will impact. The goal of this PR is to "simplify" the way we handle this "redirection back to origin" by leveraging the use of a single `destination_url` cookie set on the client-side. The changes remove scattered cookie-setting code and consolidate the redirection logic to ensure users are properly redirected back to their original page after authentication. - Centralized destination URL cookie management in routes and authentication flows - Removed manual cookie setting from various components in favor of automatic handling - Updated test scenarios to properly test the new redirection behavior
53 lines
2 KiB
Ruby
53 lines
2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# omniauth loves spending lots cycles in its magic middleware stack
|
|
# this middleware bypasses omniauth middleware and only hits it when needed
|
|
class Middleware::OmniauthBypassMiddleware
|
|
module OmniAuthStrategyCompatPatch
|
|
def callback_url
|
|
result = super
|
|
if script_name.present? && result.include?("#{script_name}#{script_name}")
|
|
result = result.gsub("#{script_name}#{script_name}", script_name)
|
|
Discourse.deprecate <<~MESSAGE
|
|
OmniAuth strategy '#{name}' included duplicate script_name in callback url. It's likely the callback_url method is concatenating `script_name` with `callback_path`.
|
|
OmniAuth v2 includes the `script_name` in the `callback_path` automatically, so the manual `script_name` call can be removed.
|
|
This issue has been automatically corrected, but the strategy should be updated to ensure subfolder compatibility with future versions of Discourse.
|
|
MESSAGE
|
|
end
|
|
result
|
|
end
|
|
end
|
|
|
|
class PatchedOmniAuthBuilder < OmniAuth::Builder
|
|
def use(strategy, *args, **kwargs, &block)
|
|
if !strategy.ancestors.include?(OmniAuthStrategyCompatPatch)
|
|
strategy.prepend(OmniAuthStrategyCompatPatch)
|
|
end
|
|
super(strategy, *args, **kwargs, &block)
|
|
end
|
|
end
|
|
|
|
def initialize(app, options = {})
|
|
@app = app
|
|
end
|
|
|
|
def call(env)
|
|
return @app.call(env) unless env["PATH_INFO"].start_with?("/auth")
|
|
|
|
# When only one provider is enabled, assume it can be completely trusted, and allow GET requests
|
|
only_one_provider = !SiteSetting.enable_local_logins && Discourse.enabled_authenticators.one?
|
|
|
|
allow_get = only_one_provider || !SiteSetting.auth_require_interaction
|
|
|
|
OmniAuth.config.allowed_request_methods = allow_get ? %i[get post] : [:post]
|
|
|
|
omniauth =
|
|
PatchedOmniAuthBuilder.new(@app) do
|
|
Discourse.enabled_authenticators.each do |authenticator|
|
|
authenticator.register_middleware(self)
|
|
end
|
|
end
|
|
|
|
omniauth.call(env)
|
|
end
|
|
end
|