Obtendo o pedido atual em trilhos de um arquivo em lib /
-
05-07-2019 - |
Pergunta
Eu coloquei todo o meu código de autenticação de usuário em um só lugar, ou seja, lib / auth.rb. Parece que este:
lib / auth.rb
module Admin
def do_i_have_permission_to?(permission)
# Code to check all of this goes here
end
end
Eu incluir este módulo como parte do ajudante aplicação, portanto, essas funções estão disponíveis em todos os pontos de vista:
application_helper.rb
require 'auth'
module ApplicationHelper
include Admin
# other stuff here
end
E eu também incluí-lo como parte do controlador do aplicativo, de modo que os controladores da mesma forma pode chamar as funções:
application.rb
require 'auth'
class ApplicationController < ActionController::Base
include Admin
end
Até agora, tão bom.
O problema é que a minha candidatura não é como um aplicativo web normal. Especificamente, mais de um usuário pode ser conectado ao sistema a partir do mesmo computador ao mesmo tempo (usando o mesmo navegador). Eu faço autenticação para ações de olhar para todas as pessoas que estão logados em que IP e se eles podem fazê-lo, ele passa.
O que isto significa é que, se um administrador quer fazer alguma coisa, que administrador tem que logar todos os outros em primeiro lugar, que é irritante. Mas queremos que o selo de administração de aprovação em tudo o administrador faz. Então a sugestão que me foi dada era para tê-lo de modo que o administrador pode fornecer uma combinação de nome de usuário / senha em qualquer página que normalmente não têm acesso a (por exemplo, uma página 'editar usuário' teria esses campos de entrada adicionais) e as rotinas de autenticação faria verificar isso. Isto significa
Admin::do_i_have_permission_to?(permission)
precisa para chegar aos parâmetros de solicitação atuais. Eu não posso simplesmente usar params [: foo] como eu faria em um controlador, porque params não é definido; semelhante request.parameters [: foo] também não vai funcionar. Minha pesquisa revelou:
- Os parâmetros atuais são na solicitação atual,
- O pedido atual está no controlador de corrente,
- O controlador atual está na despachante atual, e
- Não sei o despachante atual é mantido em qualquer lugar.
Dito isto, a experiência diz-me que quando eu estou saltando através isso muitas aros, eu estou muito provavelmente fazendo errado. Então, qual é o caminho certo para fazê-lo? Opções que eu considerados são:
- Apenas mover todas as funções atualmente em auth.rb no ApplicationHelper onde (eu acho) que terão acesso ao pedido e tal. Funciona, mas enche o inferno fora do ajudante.
- Mover todas as funções em outro lugar eles vão ver esses métodos (não sei onde)
- Eu estou simplesmente perdendo algo.
Solução
Em uma típica aplicação Rails, informações de autenticação é armazenado na sessão ativa, não os parâmetros. Como tal, é bastante simples para escrever um auxiliar que faz o que quiser.
Parece pouco ortodoxa para criar um módulo que é então incluído no ApplicationHelper. A abordagem tradicional é a de criar um ajudante separado que neste caso provavelmente seria chamado AuthenticationHelper. Este pode então ser incluído em qualquer controladores necessários, ou se preferir, carregado em ApplicationController para torná-lo disponível universalmente.
Em termos gerais, ajudantes não deve incluir outros ajudantes. É melhor do que simplesmente carregar vários ajudantes em um determinado controlador.
métodosAjudante têm acesso total a todas as variáveis ??de instância declaradas dentro do contexto de controlador que estão operando. Para ser mais específico, estes são exemplo variáveis ??somente (@Name) e não variáveis ??locais (nome). métodos auxiliares são executados por uma visão particular também.
Além disso, eu não tenho certeza por que um usuário estaria fornecendo credenciais e executar uma operação no mesmo passo, pelo menos para aplicativos tradicionais baseados na web. Normalmente, o processo é para entrar e, em seguida, executar uma ação separadamente.
No entanto, no caso de uma API onde cada transação é uma operação independente, a abordagem mais simples é fazer é puxar para fora os parâmetros de solicitação relevantes que tratam de autenticação, estabelecer algumas variáveis ??de instância controlador, e então proceder para realizar a pedido especial dadas as limitações que as credenciais impor.
A abordagem que normalmente seguem para este tipo de coisa é a camada em uma estrutura de autenticação no próprio ApplicationController que pode realizar as verificações necessárias. Estes são métodos protegidos.
Embora seja tentador para rolar em um montão deles, como can_edit_user? e can_create_group? estes muito rapidamente sair da mão. É um design mais simples para colocar em um gancho para uma can_perform de propósito geral? ou has_authority_to? método que é passada uma operação e quaisquer parâmetros necessários.
Por exemplo, uma implementação muito áspera:
class ApplicationController < ActionController::Base
protected
def has_authority_to?(operation, conditions = { })
AuthenticationCheck.send(operation, conditions)
rescue
false
end
end
module AuthenticationCheck
def self.edit_user?(conditions)
session_user == conditions[:user]
end
end
class UserController
# ...
def edit
@user = User.find(params[:id])
unless (has_authority_to?(:edit_user, :user => @user))
render(:partial => 'common/access_denied', :status => :forbidden)
end
rescue ActiveRecord::RecordNotFound
render(:partial => 'users/not_found')
end
end
Obviamente você quereria rolar um monte das verificações de autoridade em before_filter blocos de repetição evitar e para promover a coerência.
Um exemplo estrutura completa pode ser de mais ajuda, tais como o sistema de autenticação de usuário Pulseira: