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.
Foi útil?

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étodos

Ajudante 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:

http://github.com/theworkinggroup/wristband/tree/master

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top