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) 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
| 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 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) mapping = mapping.name class_eval <<-METHODS, __FILE__, __LINE__ + 1 def authenticate_ opts[:scope] = : warden.authenticate!(opts) if !devise_controller? || opts.delete(:force) end def !!current_ end def current_ @current_ end def current_ end METHODS ActiveSupport.on_load(:action_controller) do helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session" end end [查看此文件可知](https://github.com/hassox/warden/blob/master/lib/warden/proxy.rb)最后是通过获取env["rack.session"]['warden.user.user.key']来获取到当前登陆的用户的
|
Tips:
查看一个方法调用的位置:
method(:sign_in)
warden.session_serializer.method(:store).source_location
参考文档
warden wiki
warden源码解析
rack中间件warden的机制
rack安全