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?)

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!

9 comments so far

  1. Rafael Mueller August 16, 2007 9:39 am

    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. Urubatan August 16, 2007 10:09 am

    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. Jeffeson S Santos August 17, 2007 1:27 pm

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

  4. Maximiliano August 20, 2007 4:05 pm

    A outra melhoria seria usar o plugin do gem :)

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

  5. Urubatan August 20, 2007 4:11 pm

    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. seufagner August 20, 2007 4:50 pm

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

  7. seufagner August 21, 2007 6:59 pm

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

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

  9. Hospedagem July 11, 2008 9:41 pm

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

Leave a comment

Please be polite and on topic. Your e-mail will never be published.