5

認証にDevise 3.4を使用するRails 4アプリがあります。これは、ユーザーを禁止する機能でカスタマイズしました(単純なブール列users.banned、デフォルトのfalseを使用)。このUserモデルには、default_scope禁止されていないユーザーのみを返す もあります。

ここに問題があります - 禁止されたユーザーは、ログイン後に何もできなくても、ログインできるようにしたいのです (基本的に、「禁止されています」というページが表示されるだけです)。しかし、それはdefault_scopeDeviseをつまずかせているようです. ログインするか eg を呼び出すと、Devise はorauthenticate_user!のような基本的な ActiveRecord メソッドの 1 つを使用して現在のユーザーを見つけようとしますが、デフォルトのスコープ外にあるためできません。したがって、Devise はユーザーが存在しないと判断し、ログインに失敗します。findfind_by

Deviseにデフォルトのスコープを無視させるにはどうすればよいですか?

4

1 に答える 1

4

Devise と Warden のソース コードを長い間調べた後、ようやく解決策を見つけました。

簡潔な答え:

Userこれをクラスに追加します。

def self.serialize_from_session(key, salt)
  record = to_adapter.klass.unscoped.find(key[0])
  record if record && record.authenticatable_salt == salt
end

(これは ActiveRecord に対してのみテストしたことに注意してください。別の ORM アダプターを使用している場合は、おそらくメソッドの最初の行を変更する必要があります...しかし、他の ORM アダプターにその概念があるかどうかはわかりません。 「デフォルトだから

長い答え:

serialize_from_session- から User クラスに混在していますDevise::Models::Authenticatable::ClassMethods。正直なところ、それが実際に何をすべきかはわかりませんが、これは公開されたメソッドであり、Devise API で (非常にまばらに) 文書化されているため、警告なしに Devise から削除される可能性はあまりないと思います。

Devise 3.4.1 の元のソース コードは次のとおりです。

def serialize_from_session(key, salt)
  record = to_adapter.get(key)
  record if record && record.authenticatable_salt == salt
end

問題は にありますto_adapter.get(key)。は、クラスにラップされto_adapterた のインスタンスを返します。これは、本質的に を呼び出すことと同じです。(Devise はgem を使用して柔軟性を維持します。上記の方法は、ActiveRecord、Mongoid、またはその他の OrmAdapter 互換 ORM を使用しているかどうかに関係なく、変更なしで機能します。)OrmAdapter::ActiveRecordUserto_adapter.getUser.findorm_adapter

しかし、もちろん、User.finddefault_scope 内でしか検索しないため、禁止されたユーザーを見つけることができません。呼び出すとクラスが直接to_adapter.klass返され、それから呼び出してすべてのユーザーを検索し、禁止されているユーザーを Devise に表示することができます。したがって、作業行は次のとおりです。Userunscoped.find

record = to_adapter.klass.unscoped.find(key[0])

は Array (この場合は 1 つの要素) であり、Array を に渡すと Arrayが返されるため、key[0]代わりにを渡していることに注意してください。keykeyfind

またklass、実際の Devise のソース コード内で呼び出すのは悪い考えであることに注意してくださいOrmAdapter。しかし、どの ORM を使用しているか (Devise が知らないこと) を確実に知っている独自のアプリ内では、具体的に指定しても安全です。

于 2015-04-23T04:33:33.930 に答える