管理画面を作るのが面倒な Web アプリケーションで、自分のユーザに admin フラグを立てておいて無双している。アプリケーションの画面上からスパム投稿を非表示にしたり、ユーザを BAN したり。手が滑って普通の投稿を削除すると怖いので confirm を挟んだりもしている。
任意の時間にできる機能なんかも定番ですね。月初に出るバナーが本当に出るのか、割引が本当に開始するのかを、来月の時間ということにしてアクセスして確認したい。
こういうのを、自分一人ならいいが、チームで作っていると、管理者には見えているので「来月のバナーが出ちゃってます!」って勘違いで慌てる、みたいな場面も何度か目にしてきた。「管理者にしか見えないので大丈夫です」って返事したことあるよね。
問題は一般ユーザのつもりで管理者ロールを引き受けてしまっていることにある。
そこで「管理者になる」を明示的に押したときだけ「管理者モード」に入るようにしました。

管理者モードに入っているときは派手にバナー表示し続ける。
実装の肝
管理者として使っているかどうかをユーザーの属性から切り離す、がやりたいことである。
User#is_admin? は「管理者になる資格がある」を表す属性であり、これはログインしている限り常に true を返す。その上で「今この瞬間、管理者として行動している」を別のフラグで表せば実現できる。これは「セッションの一時的な状態」と考えたので session を使った。
# 管理者モードの有効化: POST /admin_mode session[:admin_mode_active] = true # 管理者モードの無効化: DELETE /admin_mode session.delete(:admin_mode_active)
今書きながら思ったけど、有効期限入れた方が良いな。管理者権限をうっかり持ち続けるリスクが更に下がる。(更に思ったけど、session ではなくレコードにして監査ログとするのも良いですね)
そして権限チェックは current_user.is_admin? && session[:admin_mode_active] になる。これは session のフラグだけで判定すると、is_admin を剥奪されたときに session が残っていると管理権限を持ったままになってしまうと考えた。
使ってみて
「管理者モードで作業するぞ!」という感覚を持ちやすくなったと思う。管理者は特別な操作をするための一時的な状態である。sudo を叩くときに一瞬だけ「本当に Enter を押していいのか?」と考えるのに近い。というかその瞬間だけ昇格するんだから本当に sudo に近いんだな。
管理者権限は「常に持っているもの」ではなく「必要なときだけ一時的に昇格するもの」だった。