サブディレクトリに別のベーシック認証をかける

サイト全体にベーシック認証をかけ、特定のサブディレクトリにのみ、違うベーシック認証をかけたかったのだが、ちょっと苦労したのでメモ。

状況

まず、状況。
ドキュメントルートは、/app/public/とする。
(htpasswdは適切な階層にそれぞれおかれているとする)

全体のベーシック認証

全体のベーシック認証は以下のようにかけていた。
/app/public/.htaccess

1
2
3
4
5
6
<If "%{HTTP_HOST} != 'dev.example.com'">
  AuthUserFile /app/.htpasswd
  AuthType Basic
  AuthName "Restricted Access"
  Require valid-user
</If>

開発環境でのみベーシック認証をかけたかったため、<If>ディレクティブにてホスト名で切り分けている。

サブディレクトリのベーシック認証

サブディレクトリのベーシック認証の設定は以下。
/app/public/subdir/.htaccess

1
2
3
4
AuthUserFile /app/public/subdir/.htpasswd
AuthType Basic
AuthName "Restricted Access"
Require valid-user

結果

サブディレクトリにアクセスすると、全体用のベーシック認証がかかった状態となってしまった。

Ifディレクティブ

色々試したり調べたりした結果、設定内容自体に間違いがあるわけではなく、実行順の問題ということがわかった。
全体のベーシック認証にて、Ifディレクティブを使用しているため特殊となっていた。

このIfディレクティブはapache2.4から使用可能になった機能となっている。
https://httpd.apache.org/docs/2.4/ja/mod/core.html#if

ドキュメントを読むと、以下のように書かれている。

<If><Files> と同じ処理順と用法になっています。

<Files>のドキュメントを参照してみると、以下の実行順となっていることが記載されていた。
https://httpd.apache.org/docs/2.4/ja/sections.html

  1. <Directory> (正規表現無し) と .htaccess を同時に (.htaccess が許可されていれば、それが を上書きします)
  2. <DirectoryMatch> (と <Directory ~>
  3. <Files><FilesMatch> を同時に
  4. <Location><LocationMatch> を同時に

ということで、<If>は3番目の実行順、となる。

よって、最初の設定での実行順を書き出してみると以下になっている事がわかる。

  1. 全体の.htaccess → ベーシックの設定なし
  2. サブディレクトリの .htaccess → ベーシック認証あり
  3. 全体の .htaccess 内の <If>ディレクティブ内 → ベーシック認証あり、上書き

このように最後に<If>ディレクティブが実行されているため、ベーシック認証が全体のものに上書きされていたということがわかった。

対応

全体のベーシック認証で、<if>ディレクティブを外すことは出来ないので、サブディレクトリのベーシック認証の設定でも、<If>ディレクティブを(無理矢理)使うことで解決させた。

サブディレクトリのベーシック認証の設定は以下のようにした。

1
2
3
4
5
6
<If true>
  AuthUserFile /app/public/subdir/.htpasswd
  AuthType Basic
  AuthName "Restricted Access"
  Require valid-user
</If>

プログラムとしては無駄なIfなのであまり綺麗な方法ではないかもしれないが…。
とりあえず、これで意図した動作をさせることが出来た。

   このエントリーをはてなブックマークに追加