前幾日所提到有關存取控制的議題有二:第5日的帳號密碼及第16日的IP範圍為依據;這兩日所都利用不少的程式碼來做判斷,才決定能做或不能做什麼動作。
如果所要寫的程式,不用那麼詳細區分什麼身份或範圍才能做什麼的話,那就只要一開始判斷條件可以,就都可以執行,而程式中的各動作就不用再處理身份、連線方面判斷的撰寫。
以第16日的範例來做延伸,如果要做一個管理者用的介面,該介面可以列出所有上傳檔案、刪除、修改設定等功能,而可以透過一組帳號密碼來使用;或者是透過某個IP就可以用的話,就可以利用 before_filter 的機制來達到上述的需求。
HTTP Basic Authentication
在 Gmail 的服務中,可將自己的信箱透過 RSS 來看目前自己有什麼新信件,而其 URL 語法是
https://帳號:密碼@mail.google.com/mail/feed/atom
而自己也想建立這個人化的 RSS ,怎麼去抓參數,就是沒讀進來,原來這種 HTTP Basic Authentication 與程式上的認證授權機制是兩回事,所以前者是沒有 logout 的機制。在 apache 裡是最常用而簡單的認證方式;而在 RoR 中的 HTTP Basic Authentication 作法是簡單的,
繼續以第16日為例,若要在同一個 controller 中,建立管理用的列所有檔,及可以刪任何檔的action的話,而
class UpfileController < ApplicationController
# 定義管理用的帳號、密碼
USER_ID, PASSWORD = "admin", "admin_password"
# 列舉這兩個 action 需要作最後一段 authenticate 的帳號密碼檢查
before_filter :authenticate, :only => [ :admin_list, :admmin_delete ]
def index
....
# 最後的 private 之中加入:
def authenticate
authenticate_or_request_with_http_basic do |id, password|
id == USER_ID && password == PASSWORD
end
end
end
上述例子是參考 http://www.tutorialspoint.com/ruby-on-rails-2.1/rails-http-basic-authentication.htm 的作法。
多組管理帳號密碼
如果希望有多組帳號密碼的話,只要把上述的 def authenticate 改成:
def authenticate
user = Admin.find_by_username(params[:user_name])
authenticate_or_request_with_http_basic do |name, pass|
name == user.login && pass == user.password
end
end
而這個 Admin,是
./script/generate model Admin login:string password:string
帳號密碼都用plain text來存的小 table;這樣就可以有多組帳號密碼來管控。
簡易的 IP 存取控制
從 before_filter 來看,是可以在要不要執行任何 action 前,來做個條件檢查,然後才判斷能不能執行,所以就可以用以下的範例,做出簡易的 IP 範圍判斷
# 以例外的列舉方式來指明這些之外的 action 都要經過 check_ip 的檢查。
before_filter :check_ip, :except => [ :index, :save_file, :XXX ]
...
private
def check_ip
# 以 regular expression 的設法來指定可執行的 IP 或範圍
unless request.env['HTTP_X_REAL_IP'] =~ /^192\.168\.1\.(101|204|77|9)$|^168\.95\.1\./
render :text => '不准看!'
end
return
end
使用時機
如果要在同一個user table來區分不同群組或角色來建置,目前是有好幾個與 roles 有關的 plugins 可以來試試看,但必須在 controller 及 view 當中,寫好有關角色介斷的動作,所以建置上也蠻費功夫。
如果所要建置的 project 不需要複雜的身份管理,甚至不需要有 user 身份管理的話,就可以利用這簡單的 before_filter 的機制,來做 IP 或帳號密碼的簡單存取控制。