View
558
Download
3
Category
Preview:
Citation preview
Desenvolvimento Web com Ruby on
Rails
João Lucas Pereira de Santanagtalk | linkedin | twitter: jlucasps
Devise
@jlucasps
Solução flexível para autenticação de usuários
Segue o padrão MVC
Totalmente integrada com o Rails
Permite várias roles autenticadas ao mesmo
tempo (user, admin, member)
Baseada em conceitos de módulos
● Database Authenticatable
○ Criptografar a senha e armazenar em
banco de dados
○ Auntenticação pode ser feita via POST ou
HTTP Basic Authentication
Devise
@jlucasps
● Token Authenticatable
○ Autenticar o usuário baseado em um token
de acesso
○ Token pode ser enviado via query string ou
HTTP Basic Authentication
Devise
@jlucasps
Devise
@jlucasps
● Omniauthable
○ Framework de autenticação compatível
com diversos providers (facebook, twitter,
openId, google, github), além dos
tradicionais username e password
Devise
@jlucasps
● Confirmable
○ Enviar email com as instruções de
confirmação de cadastro
● Recoverable
○ Alterar password do usuário e enviar
instruções de alteração
Devise
@jlucasps
● Registerable
○ Permite cadastar usuários para utilizarem
uma aplicação
○ Editar as informações de cadastro do
usuário
○ Excluir o cadastro
Devise
@jlucasps
● Rememberable
○ Mecanimo para salvar cookies e permitir
manter usuário autenticado na aplicação
● Trackable
○ Registrar quantidade de acessos, hora do
acesso e IP de origem
Devise
@jlucasps
● Timeoutable
○ Expirar a sessão caso o usuário fique um
período inativo
● Validatable
○ Validação de email e password
○ Mecanismo opcional e customizável
Devise
@jlucasps
● Lockable
○ Bloquear a conta do usuário caso haja um
certo número de tentativas frustradas de
acesso
○ Desbloqueio pode ser feito via email ou
após um período de tempo
Devise
@jlucasps
# https://github.com/plataformatec/devise# Flexible authentication solution for Rails with Wardengem 'devise'
Atualizar Gemfile
Atualizar config/environments/development.rb
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
MailCatcher
@jlucasps
# https://github.com/sj26/mailcatcher# Catches mail and serves it through a dream.gem 'mailcatcher'
Adicionar MailCatcher ao Gemfile
Atualizar config/environments/development.rbconfig.action_mailer.delivery_method = :smtpconfig.action_mailer.smtp_settings = { :address => "localhost", :port => 1025 }
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ mailcatcherStarting MailCatcher==> smtp://127.0.0.1:1025==> http://127.0.0.1:1080*** MailCatcher runs as a daemon by default. Go to the web interface to quit.
Devise
@jlucasps
Após adicionar Devise ao Gemfile, execute o
generator
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rails g devise:install create config/initializers/devise.rb create config/locales/devise.en.yml=============================================================== Some setup you must do manually if you haven't yet:....
Devise
@jlucasps
<!DOCTYPE html><html><head> <title>FirstApp</title> <%= stylesheet_link_tag "application", :media => "all" %> <%= javascript_include_tag "application" %> <%= csrf_meta_tags %></head> <body> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= render :partial => 'shared/menu_top' %> <div class="container-fluid"> <div class="row-fluid"> <%= yield :sidebar %> <%= yield %> </div> <%= render :partial => 'shared/footer' %> </div> </body></html>
Configurar /app/views/layouts/application.html.erb
Devise
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rails g devise User invoke active_record create db/migrate/20130619172147_add_devise_to_users.rb insert app/models/user.rb route devise_for :users
Adicionar Devise a algum model
Configurar Migration gerada e executá-lajlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rake db:migrate== AddDeviseToUsers: migrating ===============================================-- change_table(:users) -> 0.0590s-- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0007s== AddDeviseToUsers: migrated (0.0600s) ======================================
Devise
@jlucasps
class ApplicationController < ActionController::Base protect_from_forgery before_filter :authenticate_user! end
Configurar ApplicationController
Configurar arquivo /config/initializers/devise.rb# ==> Scopes configuration# Turn scoped views on. Before rendering "sessions/new", it will first check for# "users/sessions/new". It's turned off by default because it's slower if you# are using only default views.config.scoped_views = true
Devise
@jlucasps
user_signed_in?current_useruser_session
Métodos helpers gerados pelo Devise
Caso o model seja Member
before_filter :authenticate_member!member_signed_in?current_membermember_session
Devise
@jlucasps
jlucasps@lotus:/media/truecrypt1/handsonrails/first_app$ rails generate devise:views users invoke Devise::Generators::SharedViewsGenerator create app/views/users/shared create app/views/users/shared/_links.erb invoke form_for create app/views/users/confirmations create app/views/users/confirmations/new.html.erb create app/views/users/passwords create app/views/users/passwords/edit.html.erb
Customizar as views utilizadas pelo Devise
Devise
@jlucasps
class WelcomeController < ApplicationController before_filter :authenticate_user!, :except => [:index, :about, :contact] def index end def black render :layout => 'application_black' end def about end def contact end end
Caso queira liberar acesso para actions do WelcomeController
Devise
@jlucasps
<div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container-fluid"> <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <%= link_to "Project name", index_path, :class => "brand" %> <div class="nav-collapse collapse"> <p class="navbar-text pull-right"> <% if user_signed_in? %> Logged in as <%= link_to current_user.name edit_user_registration_path(current_user), :class => "navbar-link" %> <% else %> <%= link_to "login", new_user_session_path, :class => "btn" %> <% end %> </p> <ul class="nav"> <li class="active"><%= link_to "Home", index_path %></li> <li><%= link_to "About", about_path %></li> <li><%= link_to "Contact", contact_path %></li> </ul> </div><!--/.nav-collapse --> </div> </div></div>
Exibir link para login e usuário logado: /app/views/shared/_menu_top.html.erb
Devise
@jlucasps
<h2>Sign up</h2> <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> <%= devise_error_messages! %> <div><%= f.label :name %><br /> <%= f.text_field :name, :autofocus => true %></div> <div><%= f.label :email %><br /> <%= f.email_field :email %></div> <div><%= f.label :password %><br /> <%= f.password_field :password %></div> <div><%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation %></div> <div><%= f.submit "Sign up" %></div><% end %>
<%= render "users/shared/links" %>
Alterar tela de cadastro de usuários: /app/views/users/registrations/new.html.erb
Devise
@jlucasps
RSpec.configure do |config| # ## Mock Framework # # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: # # config.mock_with :mocha # config.mock_with :flexmock # config.mock_with :rr config.include Capybara::DSL config.include Devise::TestHelpers, :type => :controller config.include Rails.application.routes.url_helpers # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures #config.fixture_path = "#{::Rails.root}/spec/fixtures"
Testes automatizados com Devise: /spec/spec_helper.rb
Devise
@jlucasps
include Warden::Test::Helpersdef create_logged_in_user(user_sym) user = FactoryGirl.find_or_create(user_sym) login_as(user, scope: :user) userend class ActiveRecord::Base mattr_accessor :shared_connection @@shared_connection = nil def self.connection @@shared_connection || retrieve_connection endendActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
Devise support /spec/support/devise.rb
FactoryGirl
@jlucasps
# Factory_girl is a fixtures replacement with a straightforward definition syntax# https://github.com/thoughtbot/factory_girl_railsgem 'factory_girl_rails', "~> 4.0"
Adicionar factory_girl ao Gemfile
Importar factory_girl no spec_helper# This file is copied to spec/ when you run 'rails generate rspec:install'ENV["RAILS_ENV"] ||= 'test'require File.expand_path("../../config/environment", __FILE__)require 'rspec/rails'require 'rspec/autorun'require 'factory_girl'require 'factory_girl_patch'require 'capybara/rails'require 'capybara/rspec'
FactoryGirl.register_strategy(:find_or_create, FactoryGirlPatch)
FactoryGirl
@jlucasps
FactoryGirl.define do factory :user_bart, :class => User do name "Bart Simpson" email "bart@simpson.com" password "dirty_boy" password_confirmation "dirty_boy" encrypted_password BCrypt::Password.create("dirty_boy", :cost => 10) end factory :user_lisa, :class => User do name "Lisa Simpson" email "lisa@simpson.com" password "smart_girl" password_confirmation "smart_girl" encrypted_password BCrypt::Password.create("smart_girl", :cost => 10) endend
Criar factories
FactoryGirl
@jlucasps
class FactoryGirlPatch def association(runner) runner.run end def result(evaluation) evaluation.object.tap do |instance| evaluation.notify(:after_build, instance) evaluation.notify(:before_create, instance) saved_object = instance.class.where(instance.attributes.except("id", "created_at", "updated_at")).first if saved_object.present? instance.id = saved_object.id instance.created_at = saved_object.created_at if instance.respond_to?(:created_at) instance.updated_at = saved_object.updated_at if instance.respond_to?(:updated_at) else evaluation.create(instance) evaluation.notify(:after_create, instance) end end endend
Estratégia find_or_create: /lib/factory_girl_patch.rb
Devise
@jlucasps
require 'spec_helper'describe UsersController do let(:user_bart) { FactoryGirl.find_or_create(:user_bart)} before(:each) do sign_in user_bart end describe "GET index" do it "assigns @users" do saved_users = [FactoryGirl.find_or_create(:user_bart), FactoryGirl.find_or_create(:user_lisa)] get :index assigns(:users).should eq(saved_users) end endend
Testes no controller /spec/controllers/users_controller_spec.rb
Devise
@jlucasps
Testes no controller /spec/controllers/users_controller_spec.rb
jlucasps@lotus:/media/first_app$ rspec spec/controllers/users_controller_spec.rb. Finished in 0.331 seconds1 example, 0 failures Randomized with seed 5290
Desenvolvimento Web com Ruby on
Rails
João Lucas Pereira de Santanagtalk | linkedin | twitter: jlucasps
Obrigado!
Recommended