Tenho um plugin JS no meu site Discourse. Este JS usa o PocketBase para armazenar dados. O PocketBase é um serviço SQLite “serverless” que me permite armazenar arquivos e blobs JSON. O PocketBase tem um sistema de autenticação fantástico baseado em JWT, de modo que, uma vez que um usuário tenha um token de autenticação, ele pode armazenar dados com segurança diretamente no PocketBase (sem passar por um servidor de backend, etc.) diretamente do JS no lado do cliente.
Estou tentando descobrir uma maneira de gerar um login no lado do PocketBase automaticamente quando um usuário faz login no Discourse.
Minha primeira tentativa foi fazer com que o plugin JS fizesse uma chamada para um caminho no servidor e incluísse os cookies de autenticação do Discourse. Em seguida, para esse caminho, deixar o nginx proxy para um serviço (“login proxy”) que pode decodificar os cookies de autenticação e determinar quem é o usuário. Com informações de usuário verificadas, o login proxy pode então fazer uma chamada especial para o PocketBase e obter um cookie de autenticação do PocketBase, e então enviar de volta esse cookie de autenticação do PocketBase que o JS do lado do cliente pode usar para fazer solicitações subsequentes diretamente ao PocketBase.
Mas estou tendo problemas para decodificar os cookies de autenticação do Discourse (imagino que _t seja o cookie certo, mas não vejo uma maneira simples de acessar os detalhes do usuário e temo que essa estrutura possa mudar de qualquer maneira).
Existe uma maneira mais inteligente de acessar com segurança o endereço de e-mail de um usuário logado? Não acho que isso deva acontecer no lado do cliente e prefiro fazer isso no lado do servidor por razões de segurança óbvias.
Não conheço o suficiente de sua stack ou caso de uso, mas acho que já resolvi um problema semelhante antes, e algumas ideias podem ser úteis para você.
Tenho um aplicativo Next.js onde preciso que o lado do cliente tenha um JWT válido para fazer chamadas à minha API de backend se houver uma sessão do Discourse.
No meu caso, estou fazendo isso com uma única chamada fetch do lado do cliente com { credentials: "include" }, o que só funciona porque tenho tudo configurado com um único domínio e a chamada fetch segue transparentemente os redirecionamentos.
Meu cliente busca um /auth/token personalizado, que verifica a existência de _t (apenas para evitar um redirecionamento inútil, caso contrário) e retorna um redirecionamento para uma URL /session/sso_provider protegida, construída seguindo a documentação no tópico vinculado, com nonce/sso/sig, e um return_sso_url apontando para um /auth/callback personalizado, que extrairá os dados enviados pelo Discourse, construirá e retornará um token JWT que meu cliente poderá usar a partir desse momento.
Acredito que seu caso de uso possa ser resolvido de maneira semelhante.
Isso significa que preciso delegar toda a autenticação de gerenciamento de usuários para o aplicativo connect? Não tenho certeza se quero fazer isso, se for o caso.
Se o connect for apenas uma camada adicional sobre o gerenciamento de autenticação de usuários do discourse existente, então isso parece viável.
Mas, quando comecei a ler sobre o discourse connect, me preocupo que agora eu precise criar e manter um aplicativo totalmente novo para gerenciar a autenticação de usuários, e eu realmente não sei como dimensionar isso no momento.
Minha resposta assume que você está usando o Discourse como seu provedor de identidade (com suas interfaces de login/cadastro) e deseja mantê-lo assim.
No lado do Discourse, habilitá-lo é tão simples quanto
No entanto, você mencionou que está construindo um plugin.
Se você construir “um caminho no servidor” em uma nova ação de controlador em um plugin do Discourse, você pode obter o usuário da sessão, chamar terceiros e retornar o JWT para o seu cliente.
Mas, acho que isso é se eu quiser enviar meus usuários para um site secundário e gerenciar a autenticação lá.
No meu caso, tenho um trecho de JS que é executado no site do Discourse. E, quero que esse JS chame um caminho no mesmo servidor e receba um cookie de volta para o PocketBase.
Na verdade, uso um proxy Nginx na frente do Discourse, e então adicionei uma rota especial /pb/auth (por exemplo). Quando meu JS atinge essa rota, um servidor proxy de backend (que não está dentro do Discourse) aceita essa conexão e tenta decodificar o cookie de sessão _t.
Eu estava fazendo isso porque parece um pouco mais fácil do que adicionar um plugin do Discourse (tenho menos familiaridade com isso e com a configuração de desenvolvimento, etc.). Se for uma questão simples de decodificar um cookie usando hash base64 e sha, pensei que isso me daria uma carga útil segura para me dizer quem é o usuário.
Mas, se você acha que há uma maneira direta de construir um plugin que adicione essa rota ao Discourse, estou muito interessado em tentar. Parece ser o caminho certo a longo prazo. Mas, sou um velho programador Perl, então prefiro o caminho mais fácil, e minha rota Nginx pareceu mais fácil.
Tudo o contrário: se você tiver um “site” separado (PocketBase neste exemplo) e quiser que o Discourse seja a fonte da verdade para gerenciamento de usuários/autenticação – como meu exemplo Next.js.
À primeira vista, preciso perguntar: este tutorial está adicionando código à instalação base do rails para o discourse? Eu não me importo de fazer isso se for a maneira oficial, mas parece perigoso e seria melhor tratado como um plugin (que pode ser facilmente desinstalado, desativado). Além disso, não preciso me preocupar que isso quebre atualizações do discourse se meu código não estiver no repositório do github?
Por exemplo, aqui:
Isso significa que eu realmente entro no container (./launcher enter app) e edito /var/www/app/controllers/snack_controller.rb?
E, na verdade, acabei de seguir essas instruções. Não consigo fazer a rota /admin/snack.json funcionar, mesmo depois de executar ./launcher rebuild app.
Este tutorial parece ter cerca de oito anos. Esta é realmente a maneira correta de fazer as coisas?
Existem outros guias, a data no topo é a criação do tópico, mas qualquer coisa em Documentation deve estar atualizada – avise-nos se encontrar algum problema.
Você pode verificar o código do Plugin existente como referência.
Ok, tentei seguir as instruções. Tentei usar o comando rake plugin:create[pocketbase-auth]dentro do container (já que o rake não estaria disponível fora, certo). Mas, falha gravemente porque não tenho o git configurado dentro do container.
Conforme li adiante, parece que preciso especificar o repositório git do plugin para exibir um plugin na seção de administração. No entanto, ainda não cheguei ao ponto de ter uma versão minimamente funcional do plugin e não tenho as coisas em um repositório git.
EDIT: Não li com atenção e, de fato, isso requer uma configuração de desenvolvimento, o que está claramente declarado desde o início. Vou trabalhar nisso e voltarei aqui.
Suspeito que essas dificuldades ocorram porque, normalmente, os plugins são desenvolvidos em relação a uma configuração “dev” do discourse, não dentro do container docker que estou executando. Tudo bem, mas gostaria que os guias de desenvolvimento de plugins começassem com essa premissa e instruções sobre como executar dessa forma. A maneira recomendada de executar o discourse é usando docker (o que eu adoro), mas acho que há uma lacuna entre como executar as coisas dentro do docker e fazer o desenvolvimento dentro dos docs.
# rake plugin:create[pocketbase-auth]
Cloning 'https://github.com/discourse/discourse-plugin-skeleton' to '/var/www/discourse/plugins/pocketbase-auth'...
Initializing git repository...
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /var/www/discourse/plugins/pocketbase-auth/.git/
Author identity unknown
*** Please tell me who you are.
Run
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: unable to auto-detect email address (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
(See full trace by running task with --trace)