Railsで特定のメソッドにBasic認証をかける


[「gyazo-s3」を作ってみた](http://qiita.com/mattuso/items/6ae488d638ca73e15945)ときに、閲覧時のみBasic認証をかけようとした時のメモ。

どうやら`items_controller.rb`にGETとかPOSTする時のメソッドが書いてあるみたいなので確認します。

```ruby:app/controllers/items_controller.rb
class ItemsController < ApplicationController
  before_filter :authenticate!,  only: [:create, :destroy]
  before_action :set_item, only: [:show, :destroy]

  # GET /
  def index
    @items = Item.all.page params[:page]
  end

  # GET /huge.img
  def show
    url = @item.image.url
    if url.include?('http')
      # production s3
      data = open(url)
      send_data data.read, type: @item.image_content_type, disposition: 'inline'
    else
      # development,test local
      url = Rails.root.join('public/' + url.gsub!(/\?.+/, ''))
      send_file url, type: @item.image_content_type, disposition: 'inline'
    end
  end

  # POST /items
  def create
    item = Item.create_with_imagedata(params[:imagedata])
    render text: "#{request.protocol}#{request.host_with_port}/#{item.image_file_name}"
  end

  # DELETE /huge.img
  def destroy
    @item.destroy
    render text: 'destroy'
  end

  private

  def authenticate!
    if Rails.configuration.gyazo_id && params[:id] != Rails.configuration.gyazo_id
      raise 'ID is incorrect'
    end
  end

  def set_item
    filename = "#{params[:name]}.#{params[:format].to_s}"
    @item = Item.find_by_image_file_name(filename)
    raise 'not item' if @item.nil?
  end
end

```

まず、ベーシック認証に関する定義を書かなければいけないので、次のように記述します。
ID/Pass はHerokuの環境変数を使います。

```ruby
  def basic_auth
    authenticate_or_request_with_http_basic do |user,pass|
      user == ENV["BASIC_AUTH_USER"] && ENV["BASIC_AUTH_PASSWORD"]
    end
  end
```

次に、一覧と画像を表示するときに使っている`index``show`メソッドを使うときにベーシック認証をかける記述を追加します。

```ruby
  before_filter :basic_auth, only: [:index, :show]
```

まとめるとこんな感じ。

```ruby:app/controllers/items_controller.rb
class ItemsController < ApplicationController
  before_filter :basic_auth, only: [:index, :show]
  before_filter :authenticate!,  only: [:create, :destroy]
  before_action :set_item, only: [:show, :destroy]

  def basic_auth
    authenticate_or_request_with_http_basic do |user,pass|
      user == ENV["BASIC_AUTH_USER"] && ENV["BASIC_AUTH_PASSWORD"]
    end
  end

  # GET /
  def index
    @items = Item.all.page params[:page]
  end

  # GET /huge.img
  def show
    url = @item.image.url
    if url.include?('http')
      # production s3
      data = open(url)
      send_data data.read, type: @item.image_content_type, disposition: 'inline'
    else
      # development,test local
      url = Rails.root.join('public/' + url.gsub!(/\?.+/, ''))
      send_file url, type: @item.image_content_type, disposition: 'inline'
    end
  end

  # POST /items
  def create
    item = Item.create_with_imagedata(params[:imagedata])
    render text: "#{request.protocol}#{request.host_with_port}/#{item.image_file_name}"
  end

  # DELETE /huge.img
  def destroy
    @item.destroy
    render text: 'destroy'
  end

  private

  def authenticate!
    if Rails.configuration.gyazo_id && params[:id] != Rails.configuration.gyazo_id
      raise 'ID is incorrect'
    end
  end

  def set_item
    filename = "#{params[:name]}.#{params[:format].to_s}"
    @item = Item.find_by_image_file_name(filename)
    raise 'not item' if @item.nil?
  end
end
```