Discourseでユーザーがログインした際に、外部サービスのアカウント作成・ログインをトリガーする

DiscourseサイトにJSプラグインがあり、このJSはpocketbaseを使用してデータを保存しています。Pocketbaseは、ファイルやJSONブロブを保存できる「サーバーレス」SQLiteサービスです。Pocketbaseは優れたJWTベースの認証システムを備えているため、ユーザーが認証トークンを取得すると、バックエンドサーバーを経由せずに、クライアント側のJSから直接pocketbaseに安全にデータを保存できます。

Discourseにユーザーがログインしたときに、pocketbase側で自動的にログインを生成する方法を見つけようとしています。

最初の試みは、JSプラグインからサーバー上のパスに呼び出しを行い、Discourseの認証Cookieを含めることでした。次に、そのパスに対して、nginxがそれをサービス(「ログインプロキシ」)にプロキシできるようにし、そのサービスは認証Cookieをデコードしてユーザーを特定できます。検証されたユーザー情報があれば、ログインプロキシはpocketbaseに特別な呼び出しを行い、pocketbase認証Cookieを取得し、そのpocketbase認証Cookieをクライアント側のJSが後続のリクエストでpocketbaseに直接使用できるように返します。

しかし、Discourseの認証Cookieのデコードに苦労しています(_tが正しいCookieだと思いますが、ユーザーの詳細を取得する簡単な方法が見つからず、その構造が変更される可能性も心配しています)。

ログインしているユーザーのメールアドレスに安全にアクセスするための、より賢い方法はありますか?クライアント側で行うべきではないと考えており、明らかなセキュリティ上の理由からサーバー側で行うことを好みます。

スタックやユースケースについて十分な知識はありませんが、以前類似の問題を解決したことがあり、いくつかのアイデアがお役に立つかもしれません。

クライアントサイドで有効なJWTを取得し、Discourseセッションが存在する場合にバックエンドAPIを呼び出す必要があるNext.jsアプリがあります。

このために、DiscourseをIDプロバイダーとしてDiscourseConnect経由で使用しています

私の場合は、クライアントサイドの単一のfetch呼び出しで{ credentials: "include" }を使用してこれを行っています。これは、すべてを単一のドメインで設定し、fetch呼び出しがリダイレクトを透過的に追跡するためのみ機能します。

私のクライアントはカスタム/auth/tokenをフェッチします。これは、_tの存在を確認し(それ以外の場合は無意味なリダイレクトを回避するため)、リンクされたトピックのドキュメントに従って構築された保護された/session/sso_provider URLへのリダイレクトを返します。これには、nonce/sso/sig、およびDiscourseから送信されたデータを抽出し、クライアントがそれ以降使用できるJWTトークンを構築して返すカスタム/auth/callbackを指すreturn_sso_urlが含まれます。

あなたのユースケースも同様の方法で解決できると信じています。

素晴らしい、試してみます。本当にありがとうございます。

「いいね!」 1

@renato 差し支えなければ、いくつか質問させてください。

これは、ユーザー管理認証のすべてをConnectアプリに委任する必要があるということでしょうか?もしそうなら、私はそうしたくありません。

Connectが既存のDiscourseユーザー認証管理の単なる追加レイヤーに過ぎないのであれば、それは機能するように思えます。

しかし、Discourse Connectについて読み始めたとき、ユーザー認証を管理するためのまったく新しいアプリを構築・維持する必要があるのではないかと心配になり、現時点ではその範囲をどう設定すればよいかわかりません。

私の回答は、DiscourseをIDプロバイダー(ログイン/サインアップUIを使用)として使用しており、今後もそのようにしたいという前提に基づいています。

Discourse側では、有効化は次のように簡単です。

しかし、あなたはプラグインを構築していると述べました。

Discourseプラグインで新しいコントローラーアクションとして「サーバー上のパス」を構築する場合、セッションからユーザーを取得し、サードパーティに呼び出し、JWTをクライアントに返すことができます。

議論ありがとうございました。

リンクを読みました: Use Discourse as an identity provider (SSO, DiscourseConnect) - #8 by reverend_paco

しかし、これはユーザーをセカンダリサイトに送信してそこで認証を管理したい場合のことだと思います。

私の場合は、Discourseサイトで実行されるJavaScriptがあり、そのJSから同じサーバー上のパスを呼び出して、PocketBase用のCookieを取得したいと考えています。

Discourseの前にnginxプロキシを使用しており、特別なルート /pb/auth(例)を追加しました。私のJSがそのルートにアクセスすると、バックエンドプロキシサーバー(Discourse内にはない)がその接続を受け入れ、_t セッションCookieをデコードしようとします。

プラグインを追加するよりも少し簡単だと思ったので、このようにしていました(プラグインについてはあまり詳しくなく、開発セットアップなども含めて)。CookieをBase64とSHAハッシュでデコードする簡単な方法があれば、ユーザーを識別するための安全なペイロードが得られると思ったからです。

しかし、このルートをDiscourseに追加するプラグインを構築する簡単な方法があると思われる場合は、ぜひ試してみたいです。長期的にはそれが正しい方法だと思われます。しかし、私は古いPerlプログラマーなので、怠惰な方法を好み、nginxルートはより怠惰に見えました。:slight_smile:

全く逆です。別の「サイト」(この例ではPocketBase)があり、Discourseをユーザー/認証管理の信頼できる情報源にしたい場合です。私のNext.jsの例のように。

まず、以下を読むことから始めることをお勧めします。

素晴らしい、それを読んで興奮しています。サンプルスケルトンプラグイン(https://github.com/discourse/discourse-plugin-skeleton)を見始めましたが、ドキュメントが全くないため、少しがっかりしました。

一見したところ、質問があります。このチュートリアルは、Discourseの基本的なRailsインストールにコードを追加するものですか?それが公式な方法であれば、私はそれを行っても構いませんが、それは危険に思え、アンインストールや無効化が容易なプラグインとして処理される方が良いのではないでしょうか。また、私のコードがGitHubリポジトリにない場合、Discourseのアップグレードが壊れることを心配する必要はありませんか?

例えば、ここにあります:

これは、コンテナ(./launcher enter app)にジャンプして、/var/www/app/controllers/snack_controller.rbを編集する必要があることを意味しますか?

そして、実際にその指示に従いました。./launcher rebuild appを実行した後でも、/admin/snack.jsonルートを機能させることができません。

このチュートリアルは約8年前のもののように見えます。これは本当に正しい方法なのでしょうか?

他のガイドもあります。一番上の日付はトピック作成日ですが、Documentation 内のものは最新であるはずです。問題を見つけた場合はお知らせください。

参考のために、既存の Plugin のコードを確認できます。

いいえ:

まだ更新されていないようです。

ファイルは現在 https://github.com/discourse/discourse/blob/main/app/assets/javascripts/admin/addon/routes/admin-route-map.js のようです。
2020年にリネームされました。

「いいね!」 2

承知しました。指示に従ってみました。コンテナ内で rake plugin:create[pocketbase-auth] コマンドを使用しようとしました(コンテナ外では rake が利用できないため)。しかし、コンテナ内に git がセットアップされていないため、ひどく失敗します。

さらに読み進めると、管理セクションにプラグインを表示するには、プラグインの git リポジトリを指定する必要があるようです。しかし、まだまともに動作するバージョンのプラグインを作成できておらず、git リポジトリ内にファイルもありません。

編集: よく読んでいませんでした。確かにこれは開発環境が必要であり、それは最初に明記されています。それに着手し、後で戻ってきます。

これらの苦労は、通常、プラグインは Discourse の「開発」環境に対して開発されるものであり、私が実行している Docker コンテナ内ではないためだと推測しています。それは構いませんが、プラグイン開発者ガイドがその前提で始まり、その方法で実行するための指示を提供していればよかったのにと思います。推奨される Discourse の実行方法は Docker を使用することですが(それは気に入っています)、Docker 内で実行する方法と、ドキュメント内で開発を行う方法の間にはギャップがあると思います。

# rake plugin:create[pocketbase-auth]
'https://github.com/discourse/discourse-plugin-skeleton' を '/var/www/discourse/plugins/pocketbase-auth' にクローンしています...
git リポジトリを初期化しています...
hint: 初期ブランチの名前として 'master' を使用します。このデフォルトのブランチ名
hint: は変更される可能性があります。すべての
hint: 新しいリポジトリで使用する初期ブランチ名を構成するには、次のように呼び出します。
hint:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: 'master' の代わりに一般的に選択される名前は 'main'、'trunk'、
hint: 'development' です。作成されたばかりのブランチは、このコマンドで名前を変更できます。
hint:
hint: git branch -m <name>
/var/www/discourse/plugins/pocketbase-auth/.git/ に空の Git リポジトリを初期化しました
Author identity unknown

*** Please tell me who you are.

実行してください

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

アカウントのデフォルトのIDを設定します。
--global を省略すると、IDはこのリポジトリでのみ設定されます。

fatal: email address automatically detected (got 'discourse@community-public-do-vm-app.(none)')
rake aborted!
Command failed with exit 128: git
/var/www/discourse/lib/tasks/plugin.rake:356:in `system'
/var/www/discourse/lib/tasks/plugin.rake:356:in `block (2 levels) in <main>'
/var/www/discourse/lib/tasks/plugin.rake:346:in `chdir'
/var/www/discourse/lib/tasks/plugin.rake:346:in `block in <main>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => plugin:create
(full trace を実行するには --trace オプションを付けてタスクを実行してください)

アップデートのお知らせです。アドバイスに従ってプラグインを開発しました。期待どおりに動作し、必要なことをすべて実行してくれます。ご協力ありがとうございました。

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.