Allow a strategy to be added after authenticatable one and move store_location to FailureApp.

This commit is contained in:
José Valim 2009-11-22 00:49:23 -02:00
parent 3efc0ec08a
commit f3d5c1af22
4 changed files with 57 additions and 48 deletions

View File

@ -1,4 +1,6 @@
* enhancements * enhancements
* Remove store_location from authenticatable strategy and add it to failure app
* Allow a strategy to be placed after authenticatable
* [#45] Do not rely attribute? methods, since they are not added on Datamapper * [#45] Do not rely attribute? methods, since they are not added on Datamapper
== 0.5.6 == 0.5.6

View File

@ -1,31 +1,34 @@
module Devise module Devise
module FailureApp # Failure application that will be called every time :warden is thrown from
mattr_accessor :default_url # any strategy or hook. Responsible for redirect the user to the sign in
# page based on current scope and mapping. If no scope is given, redirect
# to the default_url.
class FailureApp
attr_reader :env
include Warden::Mixins::Common
cattr_accessor :default_url, :default_message, :instance_writer => false
@@default_message = :unauthenticated
# Failure application that will be called every time :warden is thrown from
# any strategy or hook. Responsible for redirect the user to the sign in
# page based on current scope and mapping. If no scope is given, redirect
# to the default_url.
def self.call(env) def self.call(env)
options = env['warden.options'] new(env).respond!
scope = options[:scope] end
message = env['warden'].try(:message) || options[:message]
params = case message def initialize(env)
when Symbol @env = env
{ message => true } end
when String
{ :message => message } def respond!
else options = @env['warden.options']
{} scope = options[:scope]
end
redirect_path = if mapping = Devise.mappings[scope] redirect_path = if mapping = Devise.mappings[scope]
"#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}" "#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}"
else else
"/#{default_url}" "/#{default_url}"
end end
query_string = Rack::Utils.build_query(params) query_string = query_string_for(options)
store_location!(scope)
headers = {} headers = {}
headers["Location"] = redirect_path headers["Location"] = redirect_path
@ -34,5 +37,29 @@ module Devise
[302, headers, ["You are being redirected to #{redirect_path}"]] [302, headers, ["You are being redirected to #{redirect_path}"]]
end end
# Build the proper query string based on the given message.
def query_string_for(options)
message = @env['warden'].try(:message) || options[:message] || default_message
params = case message
when Symbol
{ message => true }
when String
{ :message => message }
else
{}
end
Rack::Utils.build_query(params)
end
# Stores requested uri to redirect the user after signing in. We cannot use
# scoped session provided by warden here, since the user is not authenticated
# yet, but we still need to store the uri based on scope, so different scopes
# would never use the same uri to redirect.
def store_location!(scope)
session[:"#{scope}.return_to"] ||= request.request_uri if request && request.get?
end
end end
end end

View File

@ -5,40 +5,20 @@ module Devise
class Authenticatable < Warden::Strategies::Base class Authenticatable < Warden::Strategies::Base
include Devise::Strategies::Base include Devise::Strategies::Base
def valid?
super && params[scope] && params[scope][:password].present?
end
# Authenticate a user based on email and password params, returning to warden # Authenticate a user based on email and password params, returning to warden
# success and the authenticated user if everything is okay. Otherwise redirect # success and the authenticated user if everything is okay. Otherwise redirect
# to sign in page. # to sign in page.
#
# Please notice the semantic difference between calling fail! and throw :warden.
# The first does not perform any action when calling authenticate, just
# when authenticate! is invoked. The second always perform the action.
def authenticate! def authenticate!
if valid_attributes? if resource = mapping.to.authenticate(params[scope])
if resource = mapping.to.authenticate(params[scope]) success!(resource)
success!(resource)
else
fail!(:invalid)
end
else else
store_location fail!(:invalid)
fail!(:unauthenticated)
end end
end end
private
# Check if params and password are given. Others are checked inside authenticate.
def valid_attributes?
params[scope] && params[scope][:password].present?
end
# Stores requested uri to redirect the user after signing in. We cannot use
# scoped session provided by warden here, since the user is not authenticated
# yet, but we still need to store the uri based on scope, so different scopes
# would never use the same uri to redirect.
def store_location
session[:"#{mapping.name}.return_to"] ||= request.request_uri if request.get?
end
end end
end end
end end

View File

@ -12,8 +12,8 @@ class FailureTest < ActiveSupport::TestCase
assert_equal 302, call_failure.first assert_equal 302, call_failure.first
end end
test 'return redirect location based on mapping with params' do test 'return to the default redirect location' do
assert_equal '/users/sign_in', call_failure.second['Location'] assert_equal '/users/sign_in?unauthenticated=true', call_failure.second['Location']
end end
test 'uses the proxy failure message' do test 'uses the proxy failure message' do
@ -27,6 +27,6 @@ class FailureTest < ActiveSupport::TestCase
end end
test 'setup a default message' do test 'setup a default message' do
assert_equal ['You are being redirected to /users/sign_in'], call_failure.last assert_equal ['You are being redirected to /users/sign_in?unauthenticated=true'], call_failure.last
end end
end end