iT邦幫忙

DAY 16
10

Rails 的簡單任務系列 第 17

[RoR] 依連線範圍區分權限及透過密碼授權

避免成為全世界的暫存空間,在此加入連線範圍的考量及可加密碼之機制。

最後完成的截圖
圖中幾個縮寫說明:
C2C (Campus to Campus) -> 單位內上傳下載
C2O (Campus to Outside) -> 單位內上傳,全世界可下載
O2C (Outside to Campus) -> 全世界上傳,單位內下載
單位內連進,可看所有檔案列表且可連結,而有鎖或垃圾桶的小圖,是密碼對才可以下載及刪除;而有板手的小圖,是表示自己這個session上傳的檔案,可更改密碼及是否只供單位內下載。reset uptoken是測試用,把uptoken重設一次,視為另個連線,就沒板手圖,就不能改上另連線所上傳的檔案,inside 或 outside 的 where 值也會重抓一次。

單位外只能看到單位外上傳的檔案(但不能下載)以及單位內放出來可供外界下載的檔案。

新增欄位
./script/generate migration AddColUpfile
exists db/migrate
create db/migrate/20080926082033_add_col_upfile.rb

#編輯 db/migrate/20080926082033_add_col_upfile.rb
	class AddColUpfile < ActiveRecord::Migration
  def self.up
    add_column :upfiles, :uptoken, :string
    add_column :upfiles, :upip, :string
    add_column :upfiles, :target, :integer
    add_column :upfiles, :password, :string
  end

  def self.down
    remove_column :upfiles, :uptoken
    remove_column :upfiles, :upip
    remove_column :upfiles, :target
    remove_column :upfiles, :password
  end
end
# 記得再執行 rake db:migrate

uptoken: 將上傳者的那一次連線,做一個token,是為了辨識這上傳的檔案者,是屬於該上傳者。
upid: 將上傳的 ip 記錄下來
target: 以 1 2 3 來標示這個檔案可被何處下載,1 單位內上傳下載,2 單位內上傳全世界可下載,3 全世界上傳單位內下載。
password: 上傳者可以設的密碼。

改寫列出檔案的邏輯
一、檢查連線的 Session 中,有沒有這兩個值:1.where 是從單位內外來?2.uptoken 給一個 token ,如果有上傳檔案,也把這 token 存在資料庫中
二、若沒有,就產生這兩值到 Session 之中。

#在 app/controllers/sendme_controller.rb 的 def index 裡:
    if session[:uptoken].nil?
     session[:uptoken] = getuptoken
    end
    if session[:where].nil?
     session[:where] = getwhere
    end
    @myip = getip
    @uptoken = session[:uptoken]
    @where = session[:where]

三、依據 where 的值,若where是單位外,則去找所有 target 是大於 1 的項目列出,否則全部列出。
咦!大於 1 不就是列出 2 和 3,那單位外不就也可看到上傳檔?其實就是要讓外面看得到是否上傳成功,但在 view 之中將不會做出 target 屬於 2 的下載連結。而且也會在下載的動作進行檢查。

# target 1:in->in 2:in->out 3:out -> in
    if @where == 'outside'
     @files = Upfile.find_by_sql("select * from upfiles where target > 1 order by created_at desc")
    else
     @files = Upfile.find(:all, :order => 'created_at desc')
    end

而以下就是 app/views/sendme/_listitem.html.erb 的改寫,所然 query 了 target 是 2 和 3 ,但只單位外只能看到2,卻沒有下載連結。

<% if @where == 'outside' && file.target == 3%>
<%= file.filename %>
<% else %>
<%= link_to file.filename, :action => 'dl', :filetoken => file.filetoken %>
<% end %>

改寫下載檔案的邏輯
一、檢查有沒有 Session 中的 where 的值,沒有就導回 index 中寫 where 的 Session。
二、如果是單位外,又要下載的 target 不是 2 的話,就導回 index。

   if @dlfile.target != 2 && session[:where] == 'outside'
     flash[:error] = "您沒有權限下載此檔"
     redirect_to :action => 'index'
     return
   end

三、如果該檔不需密碼,則將檔案送出供下載。若要密碼則導到 dlpassform 要求填密碼

    if @dlfile.password.nil? or @dlfile.password == ''
     send_file("/home/ironman/test1/FILES/#{@dlfile.filetoken}",
                :filename => "#{@dlfile.filename}",
                :type => "#{@dlfile.filetype}",
                :stream => true,
                :disposition => "attachment")
#                :disposition => "inline")
    else
     flash[:notice] = "下載此檔案需要密碼"
     redirect_to :action => 'dlpassform', :filetoken => params[:filetoken]
    end

四、要密碼的檔案,看所輸的密碼對否,對就送,不對就回 index。

改寫上傳檔案的邏輯
1.所有上傳檔案,都會導到 change 這個 form 會問是否要設密碼,否就結束。
2.若是單位內上傳,會多個選項是只給單位下載或給全世界下載的選項,若不改就結束。

# 在def change 裡
...
   if @chfile.uptoken != session[:uptoken]
    flash[:error] = "you do not have permission to set this file"
    redirect_to :action => 'index'
   end

3.檔案列表中,若上傳者的連線 session 未曾結束掉的話,就可來設所上傳檔的密碼或單位內外:

<% if ffile.uptoken == @uptoken %>
<%= link_to image_tag("set.gif", :alt => 'set pass', :border=>0), :action => 'change', :filetoken => file.filetoken %>
<% end %>

刪除檔案就更單純些,只要 password 欄位不是空的,就同上的語法,提供刪除連結,而刪除的動作也就比對 password 欄來決定要不要做刪的動作。

管理端的作法
而管理者只要再另外做:不要檢查 password, target 的內容,而可以去列出及刪除的動作,就可以依上傳檔案的次序先後來作刪檔的動作。這樣基本所改寫適合單位內外用的暫存系統的重要功能就完整了。
其實靠著現有的範例,就可做出上述的動作;而要保護管理端的動作,除了可用第五日的作法套上外,後續再提出另外的簡易方式來保護。
如何自動去刪除舊檔,而不用人工去刪?後續再簡述可透過怎樣的機制來進行。


上一篇
[RoR] HTTP 環境變數的考量
下一篇
[RoR] 利用 before_filter 的簡單存取控制
系列文
Rails 的簡單任務33

1 則留言

0

感恩分享咯!

我要留言

立即登入留言