Basic認証　PART 2

##Basic認証のコードを改良する
前回の内容で、Basic認証をRailsアプリケーションに導入することができましたね。
ですが、現状のコードには次の2つの問題点があります。

###(1)ユーザー名・パスワードがコードに記述されている
Basic認証を実装しました！！パスワードはGithubに載ってます！！ってなったらセキュリティの意味ないですよね。(笑)
Github上の公開リポジトリでソースコードを管理している場合、コードを読める何者かに不正にBasic認証を突破される可能性があります。対策としては、コードに直接ユーザー名とパスワードを記述するのではなく、環境変数を利用する実装に切り替えて対処しましょう。

###(2)全ての環境でBasic認証を要求してしまう
Basic認証を使ってアクセスを制限したいのは、アプリケーションがデプロイされている本番環境ですよね。ですが、現在のコードでは、basic_authメソッドを使いたい環境を特に指定していないため、本番環境・テスト環境・開発環境の全てでBasic認証が働きます。開発中には自分の首を締めることにもなりますので、本番環境のみでBasic認証をするようにコードを書き換えましょう。

###ユーザー名・パスワードを環境変数にしよう
basic_authメソッド内で直接記述しているユーザー名とパスワードを環境変数に格納しましょう。

####ローカル環境の設定

```ruby:ターミナル
$ 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
```

####本番環境の設定
 ```ruby:ターミナル
# 本番環境
$ 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と入力して保存して終了
```

```ruby:ターミナル
# 本番環境
# 編集した環境変数を適用するために一旦ログアウトします。
$ 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アプリケーション側で読み込むように記述を変更しましょう。

```ruby: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を編集しましょう。

###本番環境のみでBasic認証をするようにしよう
続いて、本番環境のみでBasic認証をするようにしましょう。
まずはconfig/deploy配下のproduction.rbに追記します。（すでに追加済なら作業不要です）

```ruby: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の記述を少し変更します。

```ruby:app/controllers/application_controller.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の停止と起動も行ってから動作確認します。

```ruby:開発端末上での操作
$ bundle exec cap production deploy unicorn:stop
(デプロイ完了まで待ち、完了後に以下を実行)

$ bundle exec cap production deploy unicorn:start
```

もしうまく動かない場合は、一度AWSのコンソールからEC2を再起動し、nginx、MySQL、Unicornを手動で順番に再起動してください。
なおUnicornは以下のように起動しましょう。

```ruby:EC2上での操作
$ cd /var/www/アプリケーション名/current
$ bundle exec unicorn -c /var/www/アプリケーション名/current/config/unicorn.rb -E production -D
```

##Basic認証の問題点
Basic認証は少ない手間で認証を実現できるので、便利なのですが、安全性という観点から、完全に信頼できる認証方式ではありません。HTTP通信で定義されている仕様上、ユーザー名とパスワードが通信経路上にそのまま送られるため、漏洩のリスクがあります。また、ログアウトの概念が定義されていないため、もし必要になる場合は自力で実装する必要があるほか、複数のサーバーを跨いだ認証が難しいといった特徴も問題になります。

あくまで、必要最低限の認証機能を作成中のWebアプリケーションに実装したい場合のみ、Basic認証を利用するようにしましょう。