Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Warden - The building block behind Devise (Português)

Warden - The building block behind Devise (Português)

Praticamente toda aplicação web precisa de alguma forma de autenticação. Por isso, faz bastante sentido que existam bibliotecas para tomar conta disso, o que permite que os desenvolvedores foquem em outros problemas.
Você já deve ter ouvido falar, ou até mesmo já usou o Devise: basta instalar a gem e rodar alguns comandos, e você já tem um sistema de autenticação robusto.
O que muita gente não sabe é que por baixo dos panos o Devise utiliza uma outra gem: o Warden. Nessa palestra vou mostrar o que é o Warden, para que ele serve, e como o Devise o utiliza.

Leonardo Tegon

August 18, 2018
Tweet

More Decks by Leonardo Tegon

Other Decks in Programming

Transcript

  1. › bundle add devise › rails generate devise:install › rails

    generate devise User › rails db:migrate › rails server
  2. authentication logout session management Warden e-mail confirmation password recovery account

    registration Devise account locking account tracking session timeout
  3. “Warden is a Rack-based middleware, designed to provide a mechanism

    for authentication in Ruby web applications” - Warden’s GitHub Wiki
  4. class MyApp def call(env) status = 200 headers = {

    "Content-Type" => "application/json" } body = ['{ "text": "Olar, Guru-SP!" }'] [status, headers, body] end end run MyApp.new Aplicação Rack
  5. class MyApp def call(env) status = 200 headers = {

    "Content-Type" => "application/json" } body = ['{ "text": "Olar, Guru-SP!" }'] [status, headers, body] end end run MyApp.new { "rack.version"=>[1, 3], "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "SCRIPT_NAME"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"puma 3.11.0 Love Song", "GATEWAY_INTERFACE"=>"CGI/1.2", "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"localhost:9292", "HTTP_USER_AGENT"=>"curl/7.54.0", "HTTP_ACCEPT"=>"*/*", "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"9292" } Aplicação Rack
  6. Middleware class MyMiddleware def initialize(app) @app = app end def

    call(env) # do something with env @app.call(env) end end
  7. Middleware class MyMiddleware def initialize(app) @app = app end def

    call(env) # do something with env @app.call(env) end end #<MyApp:0x007fb8972a39e0>
  8. Aplicação de exemplo # config.ru class MyApp def call(env) status

    = 200 headers = { "Content-Type" => "application/json" } body = ['{ "text": "Olar, Guru-SP!" }'] [status, headers, body] end end run MyApp.new
  9. use Rack::Session::Cookie, secret: "warden" use Warden::Manager do |manager| manager.default_strategies :password

    manager.failure_app = FailureApp.new end run MyApp.new Configuração do Warden
  10. Serialização de sessão Warden::Manager.serialize_into_session do |user| user[:id] end Warden::Manager.serialize_from_session do

    |id| USERS.find { |user| user[:id] == id } end USERS = [ { id: 1, email: "[email protected]", password: "123", name: "Bruce Wayne" }, { id: 2, email: "[email protected]", password: "321", name: "James Gordon" } ]
  11. use Rack::Session::Cookie, secret: "warden" use Warden::Manager do |manager| manager.default_strategies :password

    manager.failure_app = FailureApp.new end run MyApp.new Configuração do Warden
  12. use Rack::Session::Cookie, secret: "warden" use Warden::Manager do |manager| manager.default_strategies :password

    manager.failure_app = FailureApp.new end run MyApp.new Configuração do Warden
  13. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  14. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  15. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  16. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  17. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  18. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  19. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  20. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  21. Métodos disponíveis dentro de strategies • params – Parâmetros da

    requisição • request – Objeto da requisição (Rack::Request) • session – Sessão da requisição • env – Hash do Rack contendo os dados da requisição
  22. • success! – Indica que a autenticação deu certo (resulta

    em halt!) • fail! – Indica que a autenticação falhou (resulta em halt!) • halt! – Interrompe a execução • redirect! – Redireciona para outra URL (resulta em halt!) • custom! – Aceita um array no formato do Rack (resulta em halt!) • pass – Ignora a strategy (padrão) Métodos disponíveis dentro de strategies
  23. Utilizando uma strategy # authenticates with the default strategy env["warden"].authenticate

    # authenticates with the `password` strategy env["warden"].authenticate(:password) # try to authenticate with the `password` strategy. # If it fails, authenticate with the `api_token` strategy env["warden"].authenticate(:password, :api_token)
  24. # devise/lib/devise/strategies/rememberable.rb def valid? @remember_cookie = nil remember_cookie.present? end def

    authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end devise sample
  25. # devise/lib/devise/strategies/rememberable.rb def valid? @remember_cookie = nil remember_cookie.present? end def

    authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end devise sample
  26. # devise/lib/devise/strategies/rememberable.rb def valid? @remember_cookie = nil remember_cookie.present? end def

    authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end devise sample
  27. # devise/lib/devise/strategies/rememberable.rb def valid? @remember_cookie = nil remember_cookie.present? end def

    authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end devise sample
  28. # devise/lib/devise/strategies/rememberable.rb def valid? @remember_cookie = nil remember_cookie.present? end def

    authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end devise sample
  29. # devise/lib/devise/strategies/rememberable.rb def valid? @remember_cookie = nil remember_cookie.present? end def

    authenticate! resource = mapping.to.serialize_from_cookie(*remember_cookie) unless resource cookies.delete(remember_key) return pass end if validate(resource) remember_me(resource) if extend_remember_me?(resource) resource.after_remembered success!(resource) end end devise sample
  30. # devise/lib/devise/strategies/database_authenticatable.rb def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed

    = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end devise sample
  31. # devise/lib/devise/strategies/database_authenticatable.rb def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed

    = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end devise sample
  32. # devise/lib/devise/strategies/database_authenticatable.rb def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed

    = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end devise sample
  33. # devise/lib/devise/strategies/database_authenticatable.rb def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed

    = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end devise sample
  34. # devise/lib/devise/strategies/database_authenticatable.rb def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed

    = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end devise sample
  35. # devise/lib/devise/strategies/database_authenticatable.rb def authenticate! resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed

    = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end devise sample
  36. use Rack::Session::Cookie, secret: "warden" use Warden::Manager do |manager| manager.default_strategies :password

    manager.failure_app = FailureApp.new end run MyApp.new Configuração do Warden
  37. use Rack::Session::Cookie, secret: "warden" use Warden::Manager do |manager| manager.default_strategies :password

    manager.failure_app = FailureApp.new end run MyApp.new Configuração do Warden
  38. class FailureApp def call(env) status = 401 headers = {

    "Content-Type" => "application/json" } body = ["Deu ruim”] [status, headers, body] end end
  39. require "warden" class MyApp def call(env) env["warden"].authenticate! user = env["warden"].user

    status = 200 headers = { "Content-Type" => "application/json" } body = ["{ \"user\": \"#{user[:name]}\" }"] [status, headers, body] end end
  40. require "warden" class MyApp def call(env) env["warden"].authenticate! user = env["warden"].user

    status = 200 headers = { "Content-Type" => "application/json" } body = ["{ \"user\": \"#{user[:name]}\" }"] [status, headers, body] end end
  41. require "warden" class MyApp def call(env) env["warden"].authenticate! user = env["warden"].user

    status = 200 headers = { "Content-Type" => "application/json" } body = ["{ \"user\": \"#{user[:name]}\" }"] [status, headers, body] end end
  42. require "warden" class MyApp def call(env) env["warden"].authenticate! user = env["warden"].user

    status = 200 headers = { "Content-Type" => "application/json" } body = ["{ \"user\": \"#{user[:name]}\" }"] [status, headers, body] end end
  43. require "warden" class MyApp def call(env) env["warden"].authenticate! user = env["warden"].user

    status = 200 headers = { "Content-Type" => "application/json" } body = ["{ \"user\": \"#{user[:name]}\" }"] [status, headers, body] end end
  44. require "warden" class MyApp def call(env) env["warden"].authenticate! user = env["warden"].user

    status = 200 headers = { "Content-Type" => "application/json" } body = ["{ \"user\": \"#{user[:name]}\" }"] [status, headers, body] end end
  45. › curl -i "localhost:[email protected]&password=123" HTTP/1.1 200 OK Content-Type: application/json Set-Cookie:

    rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRWE3ZjA3MTkzNTY2MG U1ZmE1MzZh%0AZWY5M2QzZmNjNTg1MTVhNmYwZmNmNDQyMzFiZWExNzNkOGZkND RiNmU2NTcG%0AOwBGSSIcd2FyZGVuLnVzZXIuZGVmYXVsdC5rZXkGOwBUaQY%3D %0A--ac7c6d8d93aba354ad6cff80c59ef0d1730f8938; path=/; HttpOnly Transfer-Encoding: chunked { "user": "Bruce Wayne" }
  46. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  47. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end
  48. email & senha Warden::Strategies.add(:password) do def valid? params["email"] && params["password"]

    end def authenticate! user = USERS.find do |user| user[:email] == params["email"] && user[:password] == params["password"] end if user.nil? fail!("Invalid email or password") else success!(user) end end end env["warden"].message
  49. class FailureApp def call(env) error_message = env["warden"].message status = 401

    headers = { "Content-Type" => "application/json" } body = ["Deu ruim: #{error_message}"] [status, headers, body] end end
  50. class FailureApp def call(env) error_message = env["warden"].message status = 401

    headers = { "Content-Type" => "application/json" } body = ["Deu ruim: #{error_message}"] [status, headers, body] end end
  51. class FailureApp def call(env) error_message = env["warden"].message status = 401

    headers = { "Content-Type" => "application/json" } body = ["Deu ruim: #{error_message}"] [status, headers, body] end end
  52. class FailureApp def call(env) error_message = env["warden"].message status = 401

    headers = { "Content-Type" => "application/json" } body = ["Deu ruim: #{error_message}"] [status, headers, body] end end
  53. USERS = [ { id: 1, email: '[email protected]', password: '$2a$10$eyNdqvloKRe0hlzSz5Q7VOSKTMQq9PpmegqgYNMBbe0.fRxVskP76',

    name: 'Bruce Wayne' }, { id: 2, email: '[email protected]', password: '$2a$10$alIdvOG32Z11Brn9XuX.FuDmoCyEQDLUQEWc/PdoaHvaGDjghp6ZO', name: 'James Gordon' } ]
  54. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  55. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  56. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  57. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  58. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  59. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  60. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  61. def authenticate! user = USERS.find { |user| user[:email] == params["email"]

    } return fail!("Invalid email or password") if user.nil? if BCrypt::Password.new(user[:password]).is_password?(params["password"]) success!(user) else fail!("Invalid email or password") end end
  62. › curl -i "localhost:[email protected]&password=123" HTTP/1.1 200 OK Content-Type: application/json Set-Cookie:

    rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRWRkZGY1NzBkMDM1 YTE5OTI0OGI5%0AMWU5NWM2NTdlZjAxN2QwZjE2NmNjZWU2YTNkOWFiZmI0Zj c5Y2E5MmI4OTAG%0AOwBGSSIcd2FyZGVuLnVzZXIuZGVmYXVsdC5rZXkGOwBU aQY%3D%0A--49fb8a3f9f887658cff35ee6c48d93618b044be3; path=/; HttpOnly Transfer-Encoding: chunked { "user": "Bruce Wayne" }
  63. Modelo User com muitas roles class User < ApplicationRecord has_many

    :roles def search_items(query) def add_to_wishlist(item)
  64. Modelo User com muitas roles class User < ApplicationRecord has_many

    :roles def search_items(query) def add_to_wishlist(item) def purchase!(item)
  65. Modelo User com muitas roles class User < ApplicationRecord has_many

    :roles def search_items(query) def add_to_wishlist(item) def purchase!(item) def create_item(attributes)
  66. Modelo User com muitas roles class User < ApplicationRecord has_many

    :roles def search_items(query) def add_to_wishlist(item) def purchase!(item) def create_item(attributes) def promote_item(item)
  67. Modelo User com muitas roles class User < ApplicationRecord has_many

    :roles def search_items(query) def add_to_wishlist(item) def purchase!(item) def create_item(attributes) def promote_item(item) def refund_purchase(order)
  68. Modelo User com muitas roles class User < ApplicationRecord has_many

    :roles def search_items(query) def add_to_wishlist(item) def purchase!(item) def create_item(attributes) def promote_item(item) def refund_purchase(order) end
  69. Vários modelos com devise /editors/sign_in current_editor class Editor < ApplicationRecord

    devise :editors def create_item(attributes) def promote_item(item) def refund_purchase(order) end /customers/sign_in current_customer class Customer < ApplicationRecord devise :customers def search_items(query) def add_to_wishlist(item) def purchase!(item) end
  70. Vários modelos com devise /editors/sign_in current_editor class Editor < ApplicationRecord

    devise :editors def create_item(attributes) def promote_item(item) def refund_purchase(order) end /customers/sign_in current_customer class Customer < ApplicationRecord devise :customers def search_items(query) def add_to_wishlist(item) def purchase!(item) end env["rack.session"] => {"warden.user.editor.key"=>1}
  71. Vários modelos com devise /editors/sign_in current_editor class Editor < ApplicationRecord

    devise :editors def create_item(attributes) def promote_item(item) def refund_purchase(order) end /customers/sign_in current_customer class Customer < ApplicationRecord devise :customers def search_items(query) def add_to_wishlist(item) def purchase!(item) end
  72. Vários modelos com devise /editors/sign_in current_editor class Editor < ApplicationRecord

    devise :editors def create_item(attributes) def promote_item(item) def refund_purchase(order) end /customers/sign_in current_customer class Customer < ApplicationRecord devise :customers def search_items(query) def add_to_wishlist(item) def purchase!(item) end env["rack.session"] => {"warden.user.editor.key"=>1, "warden.user.customer.key"=>2}
  73. # authenticate the :customer scope with the :api_token strategy env["warden"].authenticate(:api_token,

    scope: :customer) # if no scope is passed, :default is used env["warden"].authenticated? # check the :customer scope env["warden"].authenticated?(:customer) # fetch the customer env[“warden"].user(:customer) Utilizando scopes
  74. # logs everyone out env["warden"].logout # logs :default scope out

    env["warden"].logout(:default) # logs :customer out env[“warden"].logout(:customer) Utilizando scopes
  75. Configuração de Scopes use Warden::Manager do |config| config.default_scope = :customer

    config.scope_defaults(:customer, strategies: [:password]) config.scope_defaults( :editor, store: false, strategies: [:editor, :account_owner] ) end
  76. after_set_user Warden::Manager.after_set_user do |user, warden, opts| # do something end

    Causas env["warden"].user env["warden"].authenticate env["warden"].set_user(user)
  77. after_set_user Warden::Manager.after_set_user do |user, warden, opts| # do something end

    Causas env["warden"].user env["warden"].authenticate env["warden"].set_user(user) {:id=>1, :email=>"[email protected]", :password=>"$2a$10$eyNdqvloKRe0hlzS z5Q7VOSKTMQq9PpmegqgYNMBbe0.fRxVskP 76", :name=>"Bruce Wayne"}
  78. after_set_user Warden::Manager.after_set_user do |user, warden, opts| # do something end

    Causas env["warden"].user env["warden"].authenticate env["warden"].set_user(user)
  79. after_set_user Warden::Manager.after_set_user do |user, warden, opts| # do something end

    Causas env["warden"].user env["warden"].authenticate env["warden"].set_user(user) Warden::Proxy:70215393660020 @config={:default_scope=>:default, :scope_defaults=> {}, :default_strategies=>{:_all=>[:password]}, :inte rcept_401=>true, :failure_app=>#<FailureApp: 0x007fb8972a39e0>}
  80. after_set_user Warden::Manager.after_set_user do |user, warden, opts| # do something end

    Causas env["warden"].user env["warden"].authenticate env["warden"].set_user(user)
  81. after_set_user Warden::Manager.after_set_user do |user, warden, opts| # do something end

    Causas env["warden"].user env["warden"].authenticate env["warden"].set_user(user) {:store=>true, :event=>:authentication, :scope=>:default}
  82. # fetch env["warden"].user # authentication env["warden"].authenticate # set_user env["warden"].set_user(user) Warden::Manager.after_set_user

    except: :fetch Warden::Manager.after_set_user only: :authentication Warden::Manager.after_authentication Warden::Manager.after_set_user only: :fetch Warden::Manager.after_fetch Warden::Manager.after_set_user scope: :admin
  83. # devise/lib/devise/hooks/activatable.rb Warden::Manager.after_set_user do |record, warden, options| if record &&

    record.respond_to?(:active_for_authentication?) && ! record.active_for_authentication? scope = options[:scope] warden.logout(scope) throw :warden, scope: scope, message: record.inactive_message end end devise sample
  84. # devise/lib/devise/hooks/activatable.rb Warden::Manager.after_set_user do |record, warden, options| if record &&

    record.respond_to?(:active_for_authentication?) && ! record.active_for_authentication? scope = options[:scope] warden.logout(scope) throw :warden, scope: scope, message: record.inactive_message end end devise sample
  85. # devise/lib/devise/hooks/activatable.rb Warden::Manager.after_set_user do |record, warden, options| if record &&

    record.respond_to?(:active_for_authentication?) && ! record.active_for_authentication? scope = options[:scope] warden.logout(scope) throw :warden, scope: scope, message: record.inactive_message end end devise sample
  86. # devise/lib/devise/hooks/activatable.rb Warden::Manager.after_set_user do |record, warden, options| if record &&

    record.respond_to?(:active_for_authentication?) && ! record.active_for_authentication? scope = options[:scope] warden.logout(scope) throw :warden, scope: scope, message: record.inactive_message end end devise sample
  87. # devise/lib/devise/hooks/rememberable.rb Warden::Manager.after_set_user except: :fetch do |record, warden, options| scope

    = options[:scope] if record.respond_to?(:remember_me) && options[:store] != false && record.remember_me && warden.authenticated?(scope) Devise::Hooks::Proxy.new(warden).remember_me(record) end end devise sample
  88. # devise/lib/devise/hooks/rememberable.rb Warden::Manager.after_set_user except: :fetch do |record, warden, options| scope

    = options[:scope] if record.respond_to?(:remember_me) && options[:store] != false && record.remember_me && warden.authenticated?(scope) Devise::Hooks::Proxy.new(warden).remember_me(record) end end devise sample
  89. # devise/lib/devise/hooks/trackable.rb Warden::Manager.after_set_user except: :fetch do |record, warden, options| if

    record.respond_to?(:update_tracked_fields!) && warden.authenticated? (options[:scope]) && !warden.request.env['devise.skip_trackable'] record.update_tracked_fields!(warden.request) end end devise sample
  90. # devise/lib/devise/hooks/trackable.rb Warden::Manager.after_set_user except: :fetch do |record, warden, options| if

    record.respond_to?(:update_tracked_fields!) && warden.authenticated? (options[:scope]) && !warden.request.env['devise.skip_trackable'] record.update_tracked_fields!(warden.request) end end devise sample
  91. after_failed_fetch Warden::Manager.after_failed_fetch do |user, warden, opts| Warden::Manager.after_failed_fetch scope: :admin do

    |user, warden, opts| Causas # fails because the user isn't authenticated env["warden"].user env["warden"].user(:admin)
  92. on_request Warden::Manager.on_request do |warden| # do something end Warden::Proxy:70215393660020 @config={:default_scope=>:default,

    :scope_defaults=> {}, :default_strategies=>{:_all=>[:password]}, :inte rcept_401=>true, :failure_app=>#<FailureApp: 0x007fb8972a39e0>}
  93. before_failure Warden::Manager.before_failure do |env, opts| # do something end {

    "rack.version"=>[1, 3], "QUERY_STRING"=>"[email protected]&password=1234", "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/", "REQUEST_URI"=>"/[email protected]&password=1234", "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"9292", "PATH_INFO"=>"/unauthenticated", "warden.options"=> { :action=>"unauthenticated", :message=>"Invalid email or password", :attempted_path=>"/[email protected]&password=1234" } }
  94. Revisão • Warden é middleware de autenticação baseado em Rack

    • Uma strategy define a lógica para autenticar uma requisição
  95. Revisão • Warden é middleware de autenticação baseado em Rack

    • Uma strategy define a lógica para autenticar uma requisição • É possível configurar uma aplicação Rack para lidar com falhas de autenticação
  96. Revisão • Warden é middleware de autenticação baseado em Rack

    • Uma strategy define a lógica para autenticar uma requisição • É possível configurar uma aplicação Rack para lidar com falhas de autenticação • Scopes permitem que vários tipos de usuários estejam autenticados ao mesmo tempo
  97. Revisão • Warden é middleware de autenticação baseado em Rack

    • Uma strategy define a lógica para autenticar uma requisição • É possível configurar uma aplicação Rack para lidar com falhas de autenticação • Scopes permitem que vários tipos de usuários estejam autenticados ao mesmo tempo • Callbacks são executados em eventos de autenticação
  98. Revisão • Warden é middleware de autenticação baseado em Rack

    • Uma strategy define a lógica para autenticar uma requisição • É possível configurar uma aplicação Rack para lidar com falhas de autenticação • Scopes permitem que vários tipos de usuários estejam autenticados ao mesmo tempo • Callbacks são executados em eventos de autenticação • Exemplos do Devise
  99. Benefícios de saber como uma Gem funciona •Procurar bugs com

    mais confiança •Customizar com eficiência
  100. Benefícios de saber como uma Gem funciona •Procurar bugs com

    mais confiança •Customizar com eficiência •Contribuir para o open source ❤