Basic認証とは

##Basic認証
Basic認証とは、HTTP通信の規格に備え付けられているユーザー認証の仕組みです。
サーバーと通信が可能なユーザーとパスワードをあらかじめ設定しておき、それを知っているユーザーのみがWebアプリーションを利用できるようにすることができます。
※Ruby on Railsには、Basic認証を導入するためのメソッドが用意されており、簡単に実装できます。
### authenticate_or_request_with_http_basic
Ruby on RailsでBasic認証を実装するためのメソッドです。
ブロックを開き、ブロック内部でusernameとpasswordを設定することでBasic認証を利用できます。
サンプル

```
# 'admin'というユーザー名と、'password'というパスワードでBasic認証できるように設定
authenticate_or_request_with_http_basic do |username, password|
  username == 'admin' && password == 'password'
end
```
###Basic認証のRailsアプリケーションへの導入
authenticate_or_request_with_http_basicメソッドを利用して、開発中の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 == '2222'
    end
  end
end
```
これで、どのページにアクセスしてもBasic認証が要求されるようになりました。今回は、adminというユーザー名と2222というパスワードでBasic認証ができるように設定しています。
###Basic認証の動作の確認
application_controller.rbの記述が完了したら、実際にアプリケーションを起動し、Basic認証の動作の確認してみます。
'rails s'をした上で、適当なページにアクセスすると、ユーザー名とパスワードの入力を求めるポップアップウインドウが表示されます。間違ったユーザー名とパスワードではBasic認証できないことを確かめるために、あえて適当な文字を入力してみます。
正しく実装できていれば、もう一度Basic認証用のポップアップウインドウが表示されます。 間違った情報ではログインできないことを確認できたら、今度は正しい情報を入力してログインできるかどうかを確かめてみます。ユーザー名にadmin、パスワードに2222と入力して、もう一度ログインを試します。ルーティングに対応したページが表示されれば、Basic認証に成功です。
##Basic認証のコードの改良
①ユーザー名・パスワードがコードに記述されている
Basic認証をするための、adminというユーザー名と、そのパスワード2222がコードに記述されています。もしもGithub上の公開リポジトリでソースコードを管理している場合、コードを読める何者かに不正にBasic認証を突破されてしまいます。対策として、コードに直接ユーザー名とパスワードを記述するのではなく、環境変数を利用する実装に切り替えます。
②全ての環境でBasic認証を要求してしまう
Basic認証を使ってアクセスを制限したいのは、アプリケーションがデプロイされている本番環境でだけです。ですが、現在のコードでは、basic_authメソッドを使いたい環境を特に指定していないため、本番環境・テスト環境・開発環境の全てでBasic認証が働いてしまいます。本番環境のみでBasic認証をするようにコードを書き換えます。
###ユーザー名・パスワードを環境変数に
basic_authメソッド内で直接記述しているユーザー名とパスワードを環境変数に格納します。
**ローカル環境の設定**
ターミナル

```
$ vim ~/.bash_profile

# .bash_profileを開いたら、「i」とタイプしてインサートモードに移行

# .bash_profileの内部に次の記述を追加
export BASIC_AUTH_USER='admin'
export BASIC_AUTH_PASSWORD='2222'
# 記述を追加したら、escキーを押してインサートモードを抜け、「:wq」と入力して保存して終了する

# .bash_profileを再読み込みし、定義した環境変数を有効にする
$ source ~/.bash_profile
```
**本番環境の設定**
ターミナル

```
# 本番環境
$ ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
（ダウンロードした鍵を用いて、ec2-userとしてログイン）
$ sudo vim /etc/environment
# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。

BASIC_AUTH_USER='admin'
BASIC_AUTH_PASSWORD='2222'

# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了
```
ターミナル

```
# 本番環境
# 編集した環境変数を適用するために一旦ログアウトします。
$ exit
$ ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
# 環境変数が適用されているか確認しましょう。
$ env | grep BASIC_AUTH_USER
$ env | grep BASIC_AUTH_PASSWORD
```
※環境変数を記述するファイルが異なる理由はS3を使って画像をアップロードしているからです。
BASIC_AUTH_USERとBASIC_AUTH_PASSWORDという名前で、それぞれユーザー名とパスワードを定義しました。次は、この環境変数をRailsアプリケーション側で読み込むように記述を変更します。

```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
```
環境変数を使って、Basic認証を行えるユーザー名とパスワードを定義することができました。もう一度Basic認証を試みて、環境変数として設定したユーザー名とパスワードでログインができれば、正しく実装できています。
※環境変数は、環境ごとに設定する必要があります。開発環境でBasic認証をしたい場合はローカルの~/.bash_profileを、本番環境でBasic認証をしたい場合は本番サーバーにssh接続して、~/.bash_profileを編集します。
※Capistranoを利用して自動デプロイを行う場合、環境変数を明示的に指定する必要があります。config/deploy.rbに追記します。
###本番環境のみでBasic認証
次は、本番環境のみでBasic認証をするようにします。
まずはconfig/deploy配下のproduction.rbに追記します。（すでに追加済なら作業不要です）

```config/deploy/production.rb
class ApplicationController < ActionController::Base
  before_action :basic_auth, if: :production?   #追加部分
  protect_from_forgery with: :exception

  private

  def production?   #追加部分〜
    Rails.env.production?
  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
```
production?というメソッドを定義し、現在の環境が本番環境ならtrue、そうでないならfalseを返すように、Rails.env.production?と記述しています。そして、before_action :basic_auth の後に、 if: :production?と記述することによって、本番環境のみでbasic_authメソッドが実行されるようになります。
###Basic認証の動作確認
次は、Basic認証の動作確認をします。Basic認証を実装したブランチをマージしたら、Capistranoを用いたデプロイを行ないましょう。初めてBasic認証の動作確認をする時だけ、以下のようにデプロイをしてunicornの停止と起動も行ってから動作確認します。
開発端末上での操作

```
$ bundle exec cap production deploy unicorn:stop
(デプロイ完了まで待ち、完了後に以下を実行)

$ bundle exec cap production deploy unicorn:start
```
もしうまく動かない場合は、一度AWSのコンソールからEC2を再起動し、nginx、MySQL、Unicornを手動で順番に再起動してください。
なおUnicornは以下のように起動します。
EC2上での操作

```
$ cd /var/www/アプリケーション名/current
$ bundle exec unicorn -c /var/www/アプリケーション名/current/config/unicorn.rb -E production -D
```
##Basic認証の問題点
Basic認証は少ない手間で認証を実現できるので、便利なのですが、安全性という観点から、完全に信頼できる認証方式ではありません。HTTP通信で定義されている仕様上、ユーザー名とパスワードが通信経路上にそのまま送られるため、漏洩のリスクがあります。また、ログアウトの概念が定義されていないため、もし必要になる場合は自力で実装する必要があるほか、複数のサーバーを跨いだ認証が難しいといった特徴も問題になりえます。
あくまで、必要最低限の認証機能を作成中のWebアプリケーションに実装したい場合のみ、Basic認証を利用するようにしましょう。
参考リンク
[Basic認証 Wikipedia]
(https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC)
[Rails.env リファレンス(英語)]
(https://apidock.com/rails/Rails/env/class)