プラグインで外部サイトへリダイレクトできますか?

Discourse にユーザーがログインした後、外部 URL を呼び出してリモートサイトへのログインを試みています。必要なのは、リモートサイト上の URL にリダイレクトし、そこでログインを完了させた後に Discourse へ戻すことです。しかし、そうするとブラウザが CORS のためリダイレクトを拒否します:

Access to XMLHttpRequest at 'https://SITE/api/sso/v2/sso/jwt?' (redirected from 'https://testing.literatehosting.com/session') from origin 'https://testing.literatehosting.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

アプリの開発者たちは、私がリダイレクトのやり方を間違えている(例えば、ajax 呼び出しを使っているなど)と言っていますが、これは例えば こちら で言及されているコミットの内容と全く同じように見えます。

(またしても)行き詰まっています。

自分が単に愚かなのか、それとも相手側が Access-Control-Allow-Origin ヘッダーを送信する必要があるのか判断できません(もしそうなら、彼らのクライアントの誰もこれで動いているはずがないことになりますが、それはあまりに非現実的です)。

以下が私のコードです:

after_initialize do
  class ::SessionController
    def login(user)
      puts "\n\n\n\LOGIN happening!\n\n\n\n"
      session.delete(ACTIVATE_USER_KEY)
      log_on_user(user)

      if payload = cookies.delete(:sso_payload)
        sso_provider(payload)
      else
        if true # plugin is enabled and has api key and url
          sign_into_thinkific(user)
        else
          render_serialized(user, UserSerializer)
        end
      end
    end

    def sign_into_thinkific(user)
      # do stuff to generate payload

      redirect_to thinkific_sso_url(payload) # also tried redirect_to 
 generate_url(thinkific_sso_url(payload))

    end

    def generate_url(url, params = {})
      puts "\n\n\nGenerate URL: #{url}\n\n\n"
      uri = URI(url)
      uri.query = params.to_query
      uri.to_s
    end

    def thinkific_sso_url(payload)
      current_url="https://#{GlobalSetting.hostname}/"
      url = "https://#{SiteSetting.thinkific_site_url}/api/sso/v2/sso/jwt?jwt=#{payload}"
      url += "&return_to=#{URI.escape(current_url)}" 

      url
    end

  end
end

追記:開発者たちは、私が使っているのと同じ redirect_to を使用した Rails アプリを共有してくれました。彼らはそれが動作すると主張しています。Discourse には何か特別な仕組みがあり、Ember の内部にあるため redirect_to の挙動が異なるのでしょうか?

もちろん、何か単純な見落としがあるはずです。最新の試みは以下の通りです。

      url = thinkific_sso_url(payload)
      redirect_location = "<!DOCTYPE html><html><head><meta http-equiv=\"Refresh\" content = \"5; url='#{url}'\" /></head><body>This is my body</body></html>"
      Rails.logger.info "REDIRECTING... #{redirect_location}"

      render plain: redirect_location

redirect_location のテキストをファイルに保存してブラウザで開くと、Thinkific にログインし、Discourse にリダイレクトされます。悲しいことに、ブラウザでログインをクリックしても同じ動作はしません。

どなたかヒントをいただけませんか?

@sam さん、ご指名して申し訳ありませんが、Discourse 固有で即座に解決できるお手伝いをしていただけるような気がするのです。この件については 2 週間も取り組んでいます。

コードはプロキシを挟むことで動作するようにしましたが、これはあまり良い解決策ではないようです。

オーバーライドしている SessionController で外部サイトへ redirect_to しようとすると、CORS エラーが発生します。Thinkific からの同様のコードにはその問題は見られません。site_url/session 内からのリダイレクトには何か特別な点があるのでしょうか?あるいは、リダイレクトを JavaScript 経由で行う必要があるのでしょうか?もしそうであれば、その実現方法の方向性についてご教示いただけますでしょうか?

正直なところ、ここで何が起こっているのかよくわかりません。redirect_to は外部 URL へのリダイレクトに機能するはずです。

ああ、やだ。

確かにリダイレクトは機能しますが、CORS 違反が発生してしまいます。不思議なことに、Rails のサンプルコードでは全く同じリダイレクト処理でも CORS 違反は起きないのです。Ember 内で行うことに何か特別な理由があるのか、あるいは別の何かがあるのかと期待していたのですが。

バカバカしくも明らかな問題だったという期待は裏切られましたね。

本当にありがとうございます。大変感謝しています。

ログインモーダルが AJAX(base_url/session)で実装されているため、ブラウザが CORS ヘッダーを送信しない限り redirect_to を実行することを拒否していると、私は確信しています。

私が求めているのは、(どのように説明すればよいのか見当もつきませんが)AJAX から脱却し、ブラウザに対して通常のリダイレクトとして認識させる方法です。つまり、AJAX 内でのリダイレクトではないように見せる方法です。

あるいは、ログインページを非 AJAX のページとして実装する方法はないでしょうか?

こんにちは、@pfaffman さん

この件について進展はありましたか?私は ASP.NET Core Web API を使用した Discourse SSO ログインで同様の問題に直面しています。

Angular アプリのブラウザは、API から Angular アプリへリクエストがリダイレクトされた後(Discourse が正常に応答を返した後)に、「accept control header」が存在しないというエラーをスローしています。

Angular Web アプリ → ASP.NET API → API が Discourse SSO を呼び出す → Discourse が値を ASP.NET サーバー API に返す → API サーバーが呼び出しを Angular アプリの URL にリダイレクトする → ブラウザが「Access control origin header」が存在しないため Discourse URL にアクセスできないというエラーをスローする。

image

Discourse と ASP.NET API Web サーバーの両方で、すべての CORS 設定は正しく設定されています。

これは以前あなたが直面した問題に似ているようです。解決方法についてご教示いただければ幸いです。