rails_devise_warden_登陆解析

devise是rails用的比较多的一个用户登陆注册模块,研究了下他的登陆以及验证的策略(虽说还没有完全吃透),先记录下。
devise的具体使用可以参照他的文档
devise的认证机制是基于warden,所以要先了解一下warden才能理解。用户名以及密码的验证我们这里暂且不提,主要看一下sign_in方法做了什么,以及登陆之后下次请求是如何把已登录的信息带过来验证的。
1.先看下sign_in方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def sign_in(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
expire_data_after_sign_in!
if options[:bypass]
warden.session_serializer.store(resource, scope)
elsif warden.user(scope) == resource && !options.delete(:force)
# Do nothing. User already signed in and we are not forcing it.
true
else
warden.set_user(resource, options.merge!(scope: scope))
end
end

warden.session.store方法,会把user id存入env[‘rack.session’][‘warden.user.user.key’]中

1
2
3
4
5
6
7
8
9
10
11
12
13
# gems/warden-1.2.3/lib/warden/session_serializer.rb
def store(user, scope)
return unless user
method_name = "#{scope}_serialize"
specialized = respond_to?(method_name)
session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user)
end
#gems/warden-1.2.3/lib/warden/manager.rb
def serialize_into_session(scope = nil, &block)
method_name = scope.nil? ? :serialize : "#{scope}_serialize"
Warden::SessionSerializer.send :define_method, method_name, &block
end

2.已登陆成功之后,通过authenticate_user! 来验证是否登陆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{mapping}!(opts={})
opts[:scope] = :#{mapping}
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
end
def #{mapping}_signed_in?
!!current_#{mapping}
end
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
def #{mapping}_session
current_#{mapping} && warden.session(:#{mapping})
end
METHODS
ActiveSupport.on_load(:action_controller) do
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
end
end
#["/Users/.rvm/gems/ruby-2.3.0/gems/warden-1.2.3/lib/warden/proxy.rb", 103]
[查看此文件可知](https://github.com/hassox/warden/blob/master/lib/warden/proxy.rb)最后是通过获取env["rack.session"]['warden.user.user.key']来获取到当前登陆的用户的

Tips:

查看一个方法调用的位置:

method(:sign_in)
# ["/Users/.rvm/gems/ruby-2.3.0/gems/devise-3.4.1/lib/devise/controllers/sign_in_out.rb", 30]
warden.session_serializer.method(:store).source_location
# ["/Users/.rvm/gems/ruby-2.3.0/gems/warden-1.2.3/lib/warden/session_serializer.rb", 22]

参考文档

warden wiki
warden源码解析
rack中间件warden的机制
rack安全