nginx で サイトを認証する。
Basic認証だと不便なので、フォーム認証をする。
巷に「nginxでbasic認証してみた」の記事が溢れているけど。どう考えてもbasic認証(digest認証)よりHTTP認証(フォーム)のほうがいいと思うんですよね。nginxだけで片付くのになんでやらないんだろう。
nginx の auth_request を使う。
auth_requestで、認証が出来る。
- 認証済みの場合は、指定したURLをそのまま見せる
- 未認証の場合は、認証用のページに飛ばす。
- 認証ページが、401/403 を返せば未認証に
- 認証ページが、200(20x)を返せば認証済みに。
要は、認証ページを指定して403 / 200 を返す。
簡単!!!!
それだけ。超簡単。
ログインフォームに転送するには nginx で 401 エラーページを指定する
もしかしたらBasic/Digest認証を設定するよりもっと簡単で使いやすいのでは。
設定はこれだけ
auth_request /auth_checker.php; error_page 401 =301 https://$host/form.php?orig=$uri&$query_string;
auth_request セッションチェックURL
上記のこれで、ユーザの認証状況を確認する。
error_page 401 =302 ログインフォームURL
上記のこれで、401が来たら、302 でリダイレクトに変換して、認証ページへ飛ばしてる。
認証取得ページで、認証完了後に元のURLへ再度リダイレクトをするために、LOGIN_URL?orig=$uri&$query_string
で認証ページに元のリクエストページを保存している。
認証チェックの例
認証チェックは、セッションなどを見て、200 / 402 をチェックすればいい 使い方によっては、IPアドレスでチェックしたり、Oauthなどもできそうですよね。
例 auth_checker.php
<?php if ( empty($_COOKIE) ){ //do something for cookie } session_start(); if ( !empty($_SESSION['is_login']) ) { http_response_code(200); return ; }else{ http_response_code(401); return ; }
特定のディレクトリにだけ認証をかけたい場合
location /path/to/秘密 { auth_request /auth_checker.php; error_page 401 =302 https://$host/form.php?orig=$uri&$query_string; }
未認証のときは、単に見せない(ログイン者だけ画像が見えるなど)であれば、 error_pageのリダイレクトは無くても良い。
個人的には歓喜した。
Apache のディレクトリの一覧に保護を掛けるのが楽。 Basic認証だとiOSがパスワードを学習しないので不便なのでした。
認証を作るのが面倒くさいので、割とコレで自分ファイルにロックを掛けるだけなら、手軽でいいなとおもいます。
ファイルの共有程度に、NextCloudいれたりGoogleDrive契約するのも面倒くさい話だし。
参考資料
http://nginx.org/en/docs/http/ngx_http_auth_request_module.html
2018-05-09 更新
リダイレクトには、301 より 302 の方が良さそう。Chromeが301 リダイレクトを学習してキャッシュしてしまう。