- RailsへのBasic認証の導入についての備忘録。
- unicorn、Nginx使用。
Basic認証とは
- HTTP通信の規格に備え付けられてるユーザー認証の仕組み。
- サーバーと通信可能なユーザーとPWを設定し、ユーザーを制限する。
- Railsには、Basic認証導入のメソッドがあるので、簡単に実装できる。
authenticate_or_request_with_http_basic メソッド
- Railsで、Basic認証実装のためのメソッド。
- ブロックを開き、ブロック内部でusernameとpasswordを設定することで、Basic認証を利用できる。
例)ユーザー名:'admin'、パスワード:'password'で、Basic認証を設定する場合
authenticate_or_request_with_http_basic do |username, password|
username == 'ユーザー名' && password == 'パスワード'
end
RailsアプリへのBasic認証導入
- Basic認証によるログイン要求は、全コントローラで行いたいので、Basic認証の処理は、 application_controller.rb で、private下にメソッドとして定義し、before_actionで呼び出す形にする。
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :basic_auth
private
def basic_auth
authenticate_or_request_with_http_basic do |username, password|
username == 'admin' && password == 'pass'
end
end
end
- これで、全ページで、Basic認証が要求されるハズ。ポップアップウインドウが表示される。
Basic認証の設定変更
- 上の方法では、コード中にユーザー名・PWが記述されてるので、誰でも取得できてしまうので、環境変数で定義するべき。
- 全環境でBasic認証を要求してしまう状態。アクセス制限は本番環境のみにしたい。
1. ユーザー名、PWを環境変数にする
- basic_authメソッド内のユーザー名とPWを環境変数に格納。
- 環境変数は、環境ごとに設定する必要がある。
ローカル環境の設定(ターミナル)
% vim ~/.bash_profile /# .bash_profileを開き、「i」でインサートモードに移行
# .bash_profile内に、ユーザー名とPWの記述を追加
export BASIC_AUTH_USER='admin'
export BASIC_AUTH_PASSWORD='pass'
# 「escキー」でインサートモードを抜け、「:wq」 (保存して終了)
% source ~/.bash_profile /# .bash_profileを再読み込みし、定義した環境変数を有効にする
本番環境の設定(ターミナル)
% ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP] # ダウンロードした鍵を用い、ec2-userとしてログイン
% sudo vim /etc/environment
# 「i」でインサートモードに移行し、下記を追記。
BASIC_AUTH_USER='admin'
BASIC_AUTH_PASSWORD='pass'
# 「escapeキー」で終了後、「:wq」 (保存して終了)
# 環境変数を適用するため、一旦ログアウト。
% exit
% ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
# 環境変数が適用されたか確認
% env | grep BASIC_AUTH_USER
% env | grep BASIC_AUTH_PASSWORD
- BASIC_AUTH_USERとBASIC_AUTH_PASSWORDという名前で、ユーザー名とPWを定義したので、この環境変数をアプリ側で読み込むようにする。
controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :basic_auth
protect_from_forgery with: :exception
private
def basic_auth
authenticate_or_request_with_http_basic do |username, password|
username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]
end
end
end
- 環境変数は、環境ごとに設定する必要がある。
- 開発環境は、ローカルの ~/.bash_profile。
- 本番環境は、ssh接続し、 ~/.bash_profile に記述。
- Capistranoで自動デプロイする場合、環境変数を明示的に指定する必要がある(config/deploy/production.rbへ追記が必要)。
2. 本番環境のみでBasic認証する
config/deploy/production.rb
# server "db.example.com", user: "deploy", roles: %w{db}
server "(EC2のIPアドレス)", user: "ec2-user", roles: %w{app db web}
set :rails_env, "production"
set :unicorn_rack_env, "production"
# role-based syntax
# ==================
- これで、unicornが現在の環境を本番環境として認識するようになる。application_controllerにも追記。
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :basic_auth, if: :production? # 本番環境だけで、basic_authメソッドを実行するように変更
protect_from_forgery with: :exception
private
def production? # 現在の環境が本番環境か?のメソッドを定義
Rails.env.production? # true/falseを返す
end
def basic_auth
authenticate_or_request_with_http_basic do |username, password|
username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]
end
end
end
参)ローカルと本番環境で処理を分ける書き方
例)環境で処理を分ける
# 本番環境
if Rails.env == 'production'
# 処理内容
end
# 条件分岐
if Rails.env.development? # ローカル環境
# 処理内容
elsif Rails.env.production? # 本番環境
# 処理内容
elsif Rails.env.test? # テスト環境
# 処理内容
else # その他の環境
# 処理内容
end
動作確認
- マージ後、Capistranoでデプロイして、確認。
- 初めてBasic認証の動作確認をする時だけ、デプロイしてunicornを 停止 + 起動してから動作確認する。
ターミナル(開発端末上での操作)
% bundle exec cap production deploy unicorn:stop
# デプロイ完了後、↓を実行
% bundle exec cap production deploy unicorn:start
- 動かない時は、AWSのコンソールからEC2を再起動し、nginx、MySQL、Unicornを手動で順番に再起動する。
EC2上での操作
% cd /var/www/アプリ名/current
% bundle exec unicorn -c /var/www/アプリ名/current/config/unicorn.rb -E production -D
Basic認証の問題点
- 安全性の観点から、完全に信頼できる認証方式ではない。
- Basic認証は、HTTPで定義されている認証方法。HTTP通信で定義されてる仕様上、ユーザー名とPWが通信経路上にそのまま送られるため、漏洩リスクがある。
- ログアウトの概念が定義されてないので、必要な場合は、自力で実装する必要がある。複数サーバーを跨いだ認証が難しいという特徴も問題。
- 必要最低限の認証機能を実装したい場合のみ、Basic認証を利用する。