在 Heroku 上重置 config/initializers/doorkeeper.rb 中设置的范围

Reset scopes set in config/initializers/doorkeeper.rb on Heroku

我正在尝试在我的 OAuth2 服务中创建一个功能,开发人员可以在其中创建、读取和销毁作用域,以供使用我的服务的应用程序使用。

为了做到这一点,我创建了一个基本的 Scope 模型,我希望 Doorkeeper 更新它的 @optional_scopes / @scopes 与用户来的任何范围 creates/destroys。 (注意:范围只有在不使用时才能销毁。)

注意(TL;DR):这一切在开发中都能完美运行,但在 Heroku 的生产环境中却无法运行——所以问题的症结在于如何更新 Doorkeeper 中的实例变量通常在应用程序初始化时设置...如果可能的话!

我已将初始化程序设置为获取数据库中的所有范围并将它们设置为 optional_scopes

config/initializers/doorkeeper.rb:

Doorkeeper.configure do
  ...
  default_scopes :public
  optional_scopes( *Scope.where.not(name: 'public').map{ |s| s.name } )
  ...
end

我的 "CRD" 范围有一个基本控制器,它有一个过滤器,可以在创建或销毁范围列表后重置范围列表:

class ScopesController < ApplicationController
  after_action :set_optional_scopes, only: [ :create, :destroy ]
  ...

  def set_optional_scopes
    Doorkeeper.configuration.instance_variable_set(
      '@optional_scopes',
      Scope.where.not(name: 'public').map{ |s| s.name }
    )
  end
end

在我的链接应用程序的视图中,我有一个范围循环,它为用户提供范围复选框。 views/doorkeeper/applications/_form.html.erb:

<% Doorkeeper.configuration.optional_scopes.each do |scope| %>
  <%= check_box_tag(
    scope,
    'true',
    application_has_scope?( application, scope.to_s )
  ) %>
  <%= label_tag(
    scope,
    scope.to_s,
    class: 'no-style display-inline-block'
  ) %>
  <br>
<% end %>

请注意我是如何调用 Doorkeeper.configuration.optional_scopes 来填充复选框的。

考虑到此代码在 Heroku 实例中适当更新,我还覆盖了 Doorkeeper 的 self.configuration 方法,来自:

module Doorkeeper
  ...
  def self.configuration
    @config || (fail MissingConfiguration)
  end
  ...
end

至:

module Doorkeeper
  def self.configuration
    if @config
      # Reset the scopes every time the config is called
      @config.instance_variable_set(
        '@scopes',
        Scope.all.map{ |s| s.name }
      )
      @config
    else
      (fail MissingConfiguration)
    end
  end
end

因此,正如我上面所说,这在开发中运行良好。但是,在生产中它无法更新复选框列表,这意味着 Doorkeeper.configuration.optional_scopes 在创建操作后没有得到适当的重置。

非常感谢您的宝贵时间和帮助!

好吧,好吧,在写这个的过程中,我放慢了脚步,想出了解决办法,就在我眼前……

在覆盖 Doorkeeper 的 self.configuration 方法时,我需要做的就是重置 optional_scopes 而不是 scopes,因为 scopes 被定义为 default_scopes + optional_scopes无论如何。

所以看起来像这样:

def self.configuration
  if @config
    # Reset the scopes every time the config is called
    @config.instance_variable_set(
      '@optional_scopes',
      Scope.where.not(name: 'public').map{ |s| s.name }
    )
    @config
  else
    (fail MissingConfiguration)
  end
end

由于Doorkeeper::OAuth::Scopes 的超级class 的NoMethodError,这导致我所有的测试都失败,然后我意识到我需要重写该方法以包含数组的elsif。所以,这是该方法:

module OAuth
  class Scopes
    def +(other)
      if other.is_a? Scopes
        self.class.from_array(all + other.all)
      elsif other.is_a? Array
        self.class.from_array(all + other)
      else
        super(other)
      end
    end
  end
end

可以看到原文here.

我希望所有这些总有一天能对某人有所帮助!