Continuando de Future Social Authentication Improvements…
Estamos agora no processo de mover todas as informações de ‘contas associadas’ para uma única tabela de banco de dados. Isso ajudará a reduzir significativamente a lógica duplicada e permitirá um desenvolvimento mais rápido no futuro. Por exemplo, migrar nossa lógica central do twitter para o novo sistema reduziu o número de linhas de código de 136 para apenas 24
.
Este post não foi projetado para ser um manual de instruções passo a passo para adicionar um novo provedor de autenticação, mas terá como objetivo fornecer uma visão geral, apontando para o código-fonte relevante onde necessário.
Implementando um autenticador
Cada autenticador deve implementar uma subclasse de Auth::Authenticator. Para usar a nova lógica compartilhada, o autenticador pode, em vez disso, estender Auth::ManagedAuthenticator. Um exemplo de uma implementação básica pode ser encontrado no autenticador central do Facebook:
name, enabled? e register_middleware devem ser sobrescritos pelas classes implementadoras.
Nota: para compatibilidade com multissites, é importante que qualquer informação específica do site seja fornecida ao omniauth em um lambda
setup, em vez de ser fixada no momento da definição. Veja todos os autenticadores centrais para exemplos disso.
Toda a lógica para vincular contas externas a contas do Discourse é tratada por Auth::ManagedAuthenticator. Isso depende do provedor omniauth retornar dados no formato definido em sua documentação. Se alguma manipulação desses dados for necessária, os Autenticadores podem sobrescrever o método after_authenticate e manipular o auth_token conforme necessário. Por exemplo, o autenticador central do Twitter remove todas as informações extra do token:
Os dados são armazenados na tabela de banco de dados user_associated_accounts. provider_uid, info, credentials e extra são todos obtidos diretamente dos dados retornados pelo omniauth.
Uma vez que uma classe Authenticator tenha sido definida, ela precisa ser registrada. Isso deve acontecer cedo no ciclo de vida da aplicação e não pode acontecer dentro do método after_initialize de um plugin. O registro mínimo pode simplesmente conter uma referência ao autenticador. Em um plugin, o registro pode ser feito usando a função auth_provider. Por exemplo:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
No núcleo, o registro ocorre em discourse.rb. Uma lista completa das opções possíveis de AuthProvider pode ser encontrada aqui. O conteúdo de texto pode ser definido usando essas opções, mas é melhor fornecer strings localizáveis em client.en.yml seguindo as chaves padrão. Por exemplo:
Notas adicionais sobre ManagedAuthenticator por @fantasticfears
ManagedAuthenticator em detalhes
Você pode precisar trabalhar em algo especial para autenticação. E você gostaria de saber mais sobre ManagedAuthenticator. Basicamente, ele tem várias operações, opções e controla como os dados serão usados.
O Discourse gerencia as informações do usuário com dois controladores. Users::OmniauthCallbacksController gerencia o payload uma vez que a autenticação OAuth2 é concluída. after_authenticate é chamado aqui. can_connect_existing_user? também é usado aqui.
Há alguns métodos privados que você pode ler para entender como diferentes campos de dados funcionam.
if authenticator.can_connect_existing_user? && current_user
@auth_result = authenticator.after_authenticate(auth, existing_account: current_user)
else
@auth_result = authenticator.after_authenticate(auth)
end
UsersController tem revoke_account que usa can_revoke? e revoke. Mas para que o método revoke funcione remotamente, você precisa construir sua própria implementação.
UserAuthenticator é uma classe de serviço que ajuda a autenticar (verificando confirmação de e-mail ou caminho OAuth2) usuários. after_create_account é chamado aqui.
A lógica central permanece em after_authenticate com a classe de dados Auth::Result. Seguimos a estrutura de dados aqui. extra_data será passado para after_create_account para criar registros relacionados.
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
Ele tentará corresponder e conectar a uma conta existente.
Você pode se perguntar por que a criação automática de conta é possível, mas não há User.create. Isso é feito em UsersController#create.
authentication = UserAuthenticator.new(user, session)
O usuário é uma instância nova que será preenchida com dados de sessão preparados pelo provedor de autenticação. Confie em mim, é apenas mágica.
Migração para o novo sistema
Para fornecer uma troca sem interrupções para o novo sistema, os dados devem ser migrados do local de armazenamento antigo. Para provedores de autenticação centrais, isso pode ser tabelas dedicadas. Para plugins, isso pode ser plugin_store_rows ou oauth2_user_infos. Os dados mínimos necessários em uma linha de user_associated_accounts são provider_name, provider_uid e user_id. Para um exemplo de migração, veja:
Uma vez que o sistema ManagedAuthenticator tenha sido lançado na branch estável com a v2.2.0, começaremos a migrar os plugins oficiais de autenticação. Nesse ponto, um exemplo de migração de plugin_store_row será adicionado aqui.
Este documento é controlado por versão - sugira alterações no github.