HerokuのSinatraでBasic認証を使ってアクセス制限をかける

Heroku上にデプロイするSinatraで、Basic認証を使ってアクセス制限をかける方法について調べたのでメモ。特にHerokuに限らない方法だとは思うけど。ここだけの秘密だけど、最初普通のウェブサイトのように.htaccess.htpasswdを用意して、Herokuアプリ直下またはpublicディレクトリに入れればいけるんだろうと思って、heroku consoleから pwd とか実行してパスを取得して.htaccess.htpasswdまでのパスを書いて…とか壮大に明後日の方向な手順を踏んでた。

SinatraでのBasic認証の方法は全然違って、Rackの機能を使うみたい。

サイト全体をアクセス制限

Sinatraアプリの起動ファイル(config.ruから呼び出しているrbファイル)のどこかに、以下のような感じで書けばおk あ、もちろんトップレベルに書く必要はある。あとconfigureメソッド内でもいいみたい。

use Rack::Auth::Basic do |username, password|
  username == ENV['BASIC_AUTH_USERNAME'] && password == ENV['BASIC_AUTH_PASSWORD']
end

ユーザー名やパスワードは直に書いてもいいんだけど、Herokuの環境変数ENVに入れておくのがセキュリティ的にはよさそうかな。ローカルで試すときに煩雑になるデメリットはあるけど。ここらへん、いい方法あるのかな?

$ heroku config:add BASIC_AUTH_USERNAME="hoge" BASIC_AUTH_PASSWORD="fuga"

これでサイト上のどのページにアクセスしてもBasic認証のウィンドウが開く。

特定のパスだけ部分的にアクセス制限

特定のパスだけアクセス制限を掛ける場合は、helpersメソッドでヘルパー化して、それを呼び出すのが良いみたい。

require 'rubygems'
require 'sinatra'
helpers do
  def protect!
    unless authorized?
      response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
      throw(:halt, [401, "Not authorized\n"])
    end
  end
  def authorized?
    @auth ||=  Rack::Auth::Basic::Request.new(request.env)
    username = ENV['BASIC_AUTH_USERNAME']
    password = ENV['BASIC_AUTH_PASSWORD']
    @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [username, password]
  end
end
get '/' do
  'アクセス制限なし'
end
get '/protect' do
  protect!
  'アクセス制限あり'
end

実際やってみたページはこれ。ユーザー名とパスワードは上述のとおりhogefugaで。


Basic認証を行う簡単なサンプル - うなの日記 Sinatra: Frequently Asked Questions Sinatraで使える認証ライブラリのメモ - Hello, world! - s21g