まえがき
Rails のログイン機能を簡単に実装できる gem である Sorcery ですが、たとえば users.status や users.disabled など、ユーザーの特定の状態を考慮したログインチェックを行いたい場合、どのようにすべきでしょうか。
この記事では、カスタマイズのために自分が行った方法を記載します。
Sorcery
https://github.com/Sorcery/sorcery
どう書くか
app/controllers/application_controller.rb
など、ログイン後に共通で使用するコントローラーを対象とします。
そこに not_authenticated
を定義していたりなどしていたら、その近くにでも下記の記述を追加してみましょう。
def not_authenticated
redirect_to login_path
end
def logged_in? # <-- 追記するメソッド
(current_user && current_user[:status] != Settings.user_status_retired)
end
カスタマイズなどと大げさに言いましたが、見ての通り単に Sorcery の呼び出す logged_in?
メソッドをオーバーライドしているだけです。
おまけと注意点
オリジナルのソースはこちら。
https://github.com/Sorcery/sorcery/blob/7c5fee441e03779ee2888ecef317440cd10a17e7/lib/sorcery/controller.rb#L76-L78
Settings.user_status_retired
としている部分は、規模やお好みで変更して下さい。
上記の場合は config/settings.yml
に判定値を記載した場合の呼び出し例です。
config/initializers/constants.rb
に記載してもいいかもしれません。
また、応用的に複数のカラムを参照する場合には、以下のようにすれば良いでしょう。
def not_authenticated
redirect_to login_path
end
def logged_in?
(
current_user \
&& current_user[:status] != Settings.user_status_retired \
&& current_user[:hoge] == "piyo" # <-- ふたつ目の条件
)
end
この処理は、以下の流れにそっています。
- Sorcery で通常のログイン処理が行われ、@current_user などがセットされる。
-
application_controller.rb
のbefore_action
メソッドが、Sorcery のrequire_login
メソッドを呼び出す。 - Sorcery の
require_login
メソッドが、同logged_in?
メソッドを呼び出す。
つまり @current_user
のセットを阻害する働きはありませんし、ログイン時にセッションを発行している場合には、別途それを destroy
してやる必要があるかもしれません。
自分の対応例
def not_authenticated
reset_sorcery_session if !!current_user
redirect_to login_path
end
User.active_for_authentication? との違い
(※2017年4月14日追記)
投稿後「 User.active_for_authentication?
を使うと良いのでは」とご指摘をいただきました。
恥ずかしながら devise に明るくなく active_for_authentication?
を知らなかったので、まず試してみて、もしそれで済むならこの記事をこっそり消そうと思っていました。
devise
https://github.com/plataformatec/devise
具体的には、
def active_for_authentication?
self.status != Settings.user_status_retired
end
こういう記述を追加してみました。
その後動作を確認したところ active_for_authentication?
はログイン時にのみ評価が行われ、すでにログインしているユーザーを強制的にログアウトさせることはできませんでした。
とはいえ、ログイン時にのみ評価して、ログインを拒否するという動作を実装する場合には app/models/user.rb
に追記するほうがより簡潔に記述でき良いのではないかと思います(教えてくださった twitter@libkenta さん、ありがとうございます!)。