モデルごとにパスワード変更後の自動サインイン設定を可能に
Deviseでは、パスワード変更後の自動サインイン動作をモデル単位で制御できるようになりました。これにより、アプリケーション内の複数のユーザーモデルで異なるセキュリティポリシーを適用できます。
背景
Deviseには sign_in_after_change_password という設定があり、パスワード変更後にユーザーを自動的にサインインさせるかを制御します。しかし、この設定はグローバル設定としてのみ機能しており、モデルごとに定義された設定値が無視されていました。RegistrationsController の sign_in_after_change_password? メソッドは、常に Devise.sign_in_after_change_password を参照していたためです。
#5429 で sign_in_after_reset_password に対して同様の修正が行われており、本PRはその一貫性を保つための変更です。
技術的な変更
app/controllers/devise/registrations_controller.rb の sign_in_after_change_password? メソッドが、グローバル設定ではなくリソースクラスの設定を参照するように変更されました。
変更前:
def sign_in_after_change_password?
return true if account_update_params[:password].blank?
Devise.sign_in_after_change_password
end
変更後:
def sign_in_after_change_password?
return true if account_update_params[:password].blank?
resource_class.sign_in_after_change_password
end
Devise.sign_in_after_change_password から resource_class.sign_in_after_change_password への変更により、モデルクラスで定義された設定値が優先されるようになります。パスワードが空の場合(メールアドレスのみの更新など)は、従来通り true を返して自動サインインを許可します。
モデルごとの設定は以下のように記述します:
class User < ApplicationRecord
devise :database_authenticatable, :registerable
self.sign_in_after_change_password = false
end
テストカバレッジの追加
test/integration/registerable_test.rb に、モデル設定が正しく反映されることを検証するテストケースが追加されました。
test 'a signed in user should not be able to use the website after changing their password if resource_class.sign_in_after_change_password is false' do
swap_model_config User, sign_in_after_change_password: false do
sign_in_as_user
get edit_user_registration_path
fill_in 'password', with: '1234567890'
fill_in 'password confirmation', with: '1234567890'
fill_in 'current password', with: '12345678'
click_button 'Update'
assert_contain 'Your account has been updated successfully, but since your password was changed, you need to sign in again.'
assert_equal new_user_session_path, @request.path
assert_not warden.authenticated?(:user)
end
end
このテストは、User モデルで sign_in_after_change_password を false に設定した場合、パスワード変更後にサインアウトされることを確認します。
設計判断
リソースクラスへの委譲方式 が採用されました。グローバル設定を完全に置き換えるのではなく、モデルクラスの設定を優先する形で後方互換性を維持しています。
この実装により、既存のグローバル設定 Devise.sign_in_after_change_password をデフォルト値として使いつつ、モデル単位でオーバーライドできる柔軟性が確保されます。#5429 の sign_in_after_reset_password と同じパターンを踏襲することで、API全体の一貫性も保たれています。
まとめ
本PRは、sign_in_after_change_password の設定スコープをグローバルからモデル単位に拡張した変更です。1行の変更とテストの追加により、マルチテナントアプリケーションや異なるユーザータイプを持つシステムで、モデルごとに異なるセキュリティポリシーを適用できるようになりました。