Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

16 Aug 07 Implementando Login com Ruby on Rails (exemplo simples)

Bom, ja que fui criticado por “incentivar a utilização de JSF”, vou fazer mais alguns pequenos tutoriais de como implementar um login com outros frameworks, e este sim é para incentivar a utilização, ja que estou gostando bastante do Ruby On Rails :D

Antes de comparar os dois exemplos, lembre-se de que o Ruby On Rails te da uma estrutura pronta de aplicação, por tanto não vou precisar mostrar como configurar a base de uma aplicação como foi feito no outro exemplo

Comecemos criando uma aplicação Ruby On Rails:

$rails nomeDaAplicação

Depois, vamos criar um controller para a autenticação:

$script/generate controller login login

Isto vai criar um controller de nome login, e uma view de nome login também.

O código do login_controller.rb vai ficar mais ou menos assim:

class LoginController < ApplicationController
def index
render :action => 'login'
end
def login
end
def do_login
username = params[:username]
password = params[:password]
if username.nil? || password.nil? || username==password
redirect_to :action => "login"
flash[:notice] = 'Usuário ou senha incorretos'
else
session["user_id"] = username
redirect_to :controller => "secure", :action => "index"
end
end
end

Basicamente o controller tem implementado apenas o método do_login, que vai fazer uma validação bem complexa, de o usuário e a senha terem sido fornecidos e não serem iguais, você pode adaptar isto a sua aplicação mais tarde …

A view de login, vai ficar assim:

<% form_tag :action => 'do_login' do %>
<table align="center" class="loginForm">
<tr>
<td>
<%= image_tag "botao_login.png" %>
</td>
<td>
<input type="text" name="username"/>
</td>
</tr>
<tr>
<td>
<%= image_tag "botao_senha.png" %>
</td>
<td>
<input type="password" name="password" />
</td>
</tr>
<tr>
<td colspan="2">
<%= image_submit_tag "box_avancar.png", :style => 'width:75px;height:25px;' %>
</td>
</tr>
<table>
<% end %>

É uma view simples, apenas com um formulário e dois campos …

Ok, beleza, e como é que eu uso isto?

Vamos começar alterando application.rb, o código vai ficar assim:

class ApplicationController < ActionController::Base
# Pick a unique cookie name to distinguish our session data from others'
session :session_key => '_untitled6_session_id'
before_filter :authorize
protected
# Override in controller classes that should require authentication
def secure?
false
end
private
def authorize
if secure? && session["user_id"].nil?
session["return_to"] = request.request_uri
redirect_to :controller => "login", :action => "login"
return false
end
end
end

O que fizemos foi adicionar um filter a todos os métodos de todos os controllers, que vai interceptar a chamada a todos os métodos, e por padrão não vai fazer nada (o método secure? retorna false por padrão), caso o controller sobreescreva este método e faça-o retornar true, o filtro vai verificar se existe um user_id na sessão, se existir segue o processamento normal, caso contrário redireciona para o login.

E como utilizamos isto? vamos fazer um exemplo de um controller que vai precisar de segurança …

$script/generate controller seguro index

Para gerar um controller de nome seguro, e com uma ação de nome index.

Agora vamos alterar o código do securo_controller.rb

class SeguroController < ApplicationController
def index
end
protected
def secure?
true
end
end

Sobre escrevendo o método secure? para retornar true, fizemos com que todos os métodos deste controller precisem de autenticação para permitir o acesso.

E se quisermos que apenas alguns métodos precisem de autenticação?

Podemos utilizar algo parecido com este código:

protected
def secure?
["metodoSegro","outroMetodoSeguro"].include?(action_name)
end

Tudo pronto, login implementado …

Mas como no exemplo com JSF, ainda podemos melhorar esta implementação, por exemplo, armazenando na sessão os grupos do usuário para poder fazer uma melhor verificação dentro dos métodos …

Outra possível melhoria, seria aproveitar o atributo: session["return_to"] dentro do método do_login para redirecionar o usuário para a URL que ele tentou acessar originalmente ...

E como no último post, deixo algumas perguntas para vocês:

  1. Quais outras possíveis melhorias vocês vêem neste exemplo?
  2. Quais problemas vocês vêem nesta implementação?

Para quem estiver interessado em mais detalhes sobre Ruby On Rails, podem dar uma olhada no tutorial que eu traduzi:

Quatro dias de Ruby On Rails – Primeiro dia, Quatro dias de Ruby On Rails – Segundo dia,

Quatro dias de Ruby On Rails – Terceiro Dia, Quatro dias de Ruby On Rails – Quarto Dia

A próxima implementação de login, acho que vai ser com o Wicket, até para eu aprender um pouco sobre ele :D (seufagner, não se anima a escrever este para postar aqui?)

Você gostou deste post? Compartilhe:
Se você gostou deste post, talvez você queira assinar o feed RSS! Você também pode me seguir no Twitter.

Tags: ,

Reader's Comments

  1. |

    session["user_id"]
    session["return_to"]
    Você pode (deve?) usar símbolos session[:user_id] e session[:return_to] ao invéz de string.

    Além disso, já que você salvou a URL original, como você comentou, poderia ter utilizado abaixo para redirecionar ;P

    Eu geralmente utilizo o “skip_before_filter” nos controladores onde alguma action não precisa de autênticação ao invéz de colocar esse método “secure?”, mas isso não faz muita diferença

  2. |

    dos simbolos eu sei que posso utilizar, utilizo na maior parte dos casos :D
    não sei por que não utilizei no exemplo …
    Eu não salvei utilizei a URL por que copiei o exemplo de um sistema que estou desenvolvendo, e naquele sistema só tem uma situação que eu realmente preciso disto, na maior parte dos casos isto me causaria problemas, então deixei como exercicio, como comentei no final, que isto poderia ser melhorado :D

    e valeu a dica do skip_before_filter, eu não sabia dele :D
    acho que fica mais “polido” do que o “secure?” mesmo :D

  3. |

    Belo Post Urubatan… acho que logo logo alguem vai estar suando RoR na maioria de seus projetos hehehe

  4. |

    A outra melhoria seria usar o plugin do gem :)

    http://wiki.rubyonrails.com/rails/pages/Acts_as_authenticated

  5. |

    Verdade Maximiliano, isto seria mais fácil e mais produtivo :D
    mas a idéia deste post era apresentar a base do funcionamento :D
    Inclusive o act_as_authenticated trabalha com conceitos bem parecidos :D

  6. |

    Eu to escrevendo um post sobre Wicket e vou usar um sisteminha de login para mostrar alguns conceitos dele… Boa sugestao :-)

  7. |

    […] Assim como JSF, Tapestry e ASP.NET, o Wicket é um framework […]

  8. |

    [...] Implementando Login com Ruby on Rails (exemplo simples) [...]

  9. |

    Gostei mesmo, como essas iniciativas a linguagem começa a crescer.

  10. |

    muito bom o post!!!
    eu não entendi a utilidade de:
    session :session_key => ‘_untitled6_session_id’

    serve para que? poderia explicar?

  11. |

    Cara, eu achei interessante.

    Eu tentei fazer aqui, mas estou com problema no routes.

    No caso, para testar fica localhost:3000/login/

    e no routes.rb

    map.connect ‘:controller/’

    ou seja, ao colocar localhost:3000/login/ ele “chama” (nao sei se o termo é esse) o controller login.

    a criação do banco. Qual o nome da tabela? Eu criei, login por exemplo. Não foi. Depois dá erro.

    No route matches “/secure” with {:method=>:get}

    Desculpe a dúvida, é que estou começando… caso tenha saco para tirar a dúvida. Acredito que você responde em 2 minutos.

    []s!

  12. |

    Sugiro você primeiro seguir o tutorial, depois tentar altera-lo.

  13. |

    Urubatan, comprei seu livro e estou estando rails. Nao conseguir colocar o exemplo do login do livro, e tao pouco esse simples exemplo ai em cima.

    como proteger uma outro controller, tenho por exemplo uma controller chamada cliente onde colocar os textos , como no exemplo, sugerido. explica ai amigao, fico agradecido.

    class SeguroController < ApplicationController
    def index
    end
    protected
    def secure?
    true
    end
    end

  14. |

    No meu, seguindo todos os passos, voltou a seguinte frase: “Unknown action – No action responded to index. Actions: do_login and login”

    O que está acontecendo? Sou iniciante em RoR e confesso que me perdi.