Devise の認証ロジックをカスタマイズしてみた。
認証ロジックを独自実装する方法を会得すると devise のカスタマイズの幅が大きく広がる。
試作した全ソースコードは https://github.com/katoy/rails-canvas にある。
- test を書く
- config/initializers/devise.rb で 認証ロジックのメソッドを指定する。
- 認証ロジックを実装する。
ここでは、username で login 制限をつけてみた。
user_02, user_04, user_06, user_08 をログイン禁止にする。
(実際にはこんな制限をつけることはないだろうが、ロジックを簡単にする為に。)
$ rake db:fixtures:load
で user_01, user_02, ... を登録できます。
(定義される内容は test/fixtures/user.yml を参照すること)
- test を書く
user_02 はログインできないこと、 user_01 はログインできること をテストする。
test/integration/devise_test.rb
...
test 'user_02 can not login' do
post '/users/sign_in', user: { username: 'user_02', password: '123123' }, format: 'js'
# assert that the response code was status code 401 (unauthorized)
assert_response 401
end
test 'user_01 can login' do
post '/users/sign_in', user: { username: 'user_01', password: '123123' }
assert_response :success
end
...
- 認証ロジックのメソッドを指定する。
以下の行を追加
config/initializers/devise.rb
...
require Rails.root.join('app/controllers/local_devise/local_authenticatable')
...
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :local_authenticatable
end
...
- 認証ロジックを実装する。
devise 内にある database での認証ロジックに手を加えた実装をする。
app/controllers/local_devise/local_authenticatable.rb
# -*- coding: utf-8 -*-
require 'devise/strategies/authenticatable'
# See
# https://github.com/plataformatec/devise/blob/master/lib/devise/strategies/database_authenticatable.rb
# http://qiita.com/hattorix@github/items/f383afdef336975bd669#2-3
# ログインチェック方法を独自に定義する。
# databas_authenticable を ベースにして、ログイン許可のアカウントチェックを追加する。
# config/initializers/devise.rb 中で、このチェックメソッドをつかうことを設定する必要がある。
module Devise
module Strategies
# Devise 標準の DatabaseAuthenticatable に サーバータイプ別のアカウントチェックを追加。
class LocalAuthenticatable < Authenticatable
def authenticate!
resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
encrypted = false
if validate(resource){ encrypted = true; validate_resource(resource) }
resource.after_database_authentication
success!(resource)
end
mapping.to.new.password = password if !encrypted && Devise.paranoid
fail(:not_found_in_database) unless resource
end
# ログインチェックのロジック
def validate_resource(resource)
# user_0[2468]* のユーザーは login 不可にする。
return false if /user_0[2468]/ =~ resource.username
# パスワードのチェック
resource.valid_password?(password)
end
end
end
end
Warden::Strategies.add(:local_authenticatable, Devise::Strategies::LocalAuthenticatable)
$ rake test でテストを実行する。