当用户已经通过身份验证时,在设计中运行典狱长策略

23t*_*tux 5 ruby ruby-on-rails devise warden

我正在使用 devise 通过用户名/密码或几个 OAuth 提供商来验证我的用户。现在我必须支持在标头内使用令牌的自定义身份验证策略。

module WardenStrategies
  class ApiKey < Warden::Strategies::Base
    def valid?
      api_token.present?
    end

    def authenticate!
      user = User.find_by(api_token: api_token)

      if user
        success!(user)
      else
        fail!("Invalid email or password")
      end
    end

    private

    def api_token
      env["HTTP_AUTHORIZATION"].to_s.remove("Bearer ")
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我添加了策略来设计和看守

# config/initializers/devise.rb
Devise.setup do |config|
  # ...
  config.warden do |manager|
    manager.default_strategies(:scope => :user).unshift :api_key
  end
  # ...
end
Run Code Online (Sandbox Code Playgroud)
# config/initializers/warden.rb
Warden::Strategies.add(:api_key, WardenStrategies::ApiKey)
Run Code Online (Sandbox Code Playgroud)

现在的问题是:我在同一站点上有一个 Playground,它通过 JavaScript 向我的 API 发送请求。在 Playground 中,我可以为不同的用户提供自定义 API 密钥。但是,当用户已经通过正常会话登录时,warden 不再运行该策略,因为它已经分配了一个用户。

那么,即使用户已经通过身份验证,我怎样才能强制典狱长/设计尝试策略呢?

Vas*_*fed 2

在调用任何策略之前,典狱长会检查会话中是否已经存在存储的用户(来自之前的请求,其中某些store?=true(默认值)的策略已成功)

您可以尝试通过以下方式伪造“未设置”用户(无需完全注销):

# manager is Warden::Manager
manager.prepend_on_request do |proxy|
  proxy.set_user(nil, scope: :user, store: false) if proxy.env["HTTP_AUTHORIZATION"].present?
end
Run Code Online (Sandbox Code Playgroud)

附言。你的策略可能还应该有def store?; false; end,因为每个请求通常都需要 api 密钥,并且也不应该导致持久会话