來談談REST、RBAC下的URL權限控制

從幾個月前開始接觸REST,到現在嘗試去設計、開發一個RESTful的web應用。說實話,到目前爲止我還對REST理解的很淺很淺。今天偶爾又去翻了翻互動百科對REST的描述,感覺那位網友寫的真好,但是有些觀點我還是有不同的意見。
互動百科上關於REST的頁面:[url]http://www.hudong.com/wiki/REST[/url]

1.上面比較後面的一句話裏說到:如果我們可以把所有的用戶需求都可以抽象爲資源,那麼MVC就可以退出歷史的舞臺了。如果情況相反,那麼我們就需要混合使用REST和MVC。

我個人看到這句話後,立馬覺得不可思議,什麼時候MVC和資源槓上了?甚至到達了非彼即此的地步!MVC僅僅是一種分層結構而已,它只是隔離了用戶界面和真正的業務邏輯代碼,然後靠控制器來連接這兩者,在這個分層裏,完全沒有涉及到資源哇,注意我這裏說”涉及“,並不是說MVC中不可能出現資源的概念。所以我很有疑問,假設用戶需求(web應用裏,用戶需求=http請求響應)都能抽象成資源,那麼MVC就可以退出歷史的舞臺了,這句話說的太過了,資源和MVC根本就不是對立的。在REST中,資源被URL標識,用戶依靠url來發出請求,請求到達服務器,服務器提供相應的url處理並響應,這個過程你可以設計成MVC模式的,也可以設計成最噁心的頁面寫代碼的模式,例如你完全可以將url直接發到某個jsp上面嘛。然後邏輯代碼全都寫在頁面上。你敢說這不是RESTful的嘛?在MVC Model1的年代裏,JSP頁面既充當控制器,又充當視圖,JavaBean封裝業務邏輯,在那個架構中,也完全可以RESTful。所以這兩者完全不是非彼即此的關係。

2.REST的核心問題是如何抽象資源。

關於這點我表示很贊成。資源是一個很抽象的東東。極端點的,可以認爲任何能夠被標識的東東都能被抽象成資源。說到這裏,我其實很想談談在我前一篇文章裏有個朋友問到”分頁權限控制“問題,說基於RBAC的權限控制很難、甚至無法對分頁適用。詳情看[url]http://www.iteye.com/topic/1112793[/url]二樓,當時我也一下子表示不太明白。現在回頭想想,其實RBAC的權限控制本身是適合的,關鍵問題是,他們在解決分頁權限這種涉及到數據級別的權限控制問題上,總是想用sql語句來解決它!

我嘗試假想一下下面這種場景:
實體:新聞(id,分類,標題,內容,作者)
實體:分類(id,名稱)
實體關係:新聞(多)—>分類(一)
REST:
用戶需求 url設計
分頁查看所有新聞 news/index/{pageNum} GET
分頁查看某類新聞 news/{cate}/index/{pageNum} GET
查看某篇新聞 news/{id} GET
查詢所有新聞且是分頁的 news/search/{keyword}/{pageNum} GET
發表新聞 news POST
刪除新聞 news/{id} DELETE
修改新聞 news/{id} PUT

這裏我可能比較極端,盡力在避免url含有?後面的參數,因爲http的url是?前面部分。既然要用url唯一標識資源,那麼肯定不能靠兩個相同的url,不同的?參數來標識,因爲在http中(至少在tomcat)中,這兩者是一樣的。除非你自己實現一個判斷url+?後面參數來保證url的唯一性,但是http方法中的POST、GET、PUT、DELETE卻可以。雖然後兩者瀏覽器不支持,但是http協議包含。

回到前面的場景,上次在我那帖子裏,那位朋友說到分頁權限控制問題。在這裏我利用上面的場景,模擬一下他說的情況,當然不一定理解到他的意思。

現在有一個新的需求:在後臺登陸用戶中,信息發佈員角色的用戶只能查看作者爲自己的新聞。

問題來了:在我們前面設計的url中,分頁查看某類新聞或者分頁查看所有新聞中都沒有關於新聞作者的權限控制。那麼,這時候我們該怎麼辦?

好多人可能會:在代碼裏保證(sql語句裏),盡力滿足新的需求,但是這樣問題更多了,這時候權限控制就麻煩了,因爲此時很明顯的基於url的權限控制模型無效了!因爲這時候你不是靠url來控制權限,而是通過sql語句了。

我個人是非常不贊同這種做法的,這種做法很噁心,雖然交給sql語句來做看起來不錯。嗯,是的,我並不反對通過sql語句來輔助,但是我反對通過sql語句來控制權限。注意這裏我強調的是”sql語句控制權限“。在我的那篇文章裏似乎表達的應該是基於url來控制。因爲在我看來,確實web應用系統裏所有的需求都能被抽象成資源,用url來標識。

關鍵點出來了,需求——>抽象——>資源<——URL標識。

那麼,上面新的需求是:在後臺登陸用戶中,信息發佈員角色的用戶只能查看作者爲自己的新聞。下面我們的任務將是如何來把這個需求抽象成資源,而不是想法設法的去動其他需求裏寫好的代碼。

我個人會這麼做:該新的需求中影響到了它的另外幾個需求,把被影響的兩個url的權限從信息發佈員用戶權限中去除。新定義兩個url,分配給該用戶。具體做法是:

角色爲信息發佈員的用戶:
分頁查看所有新聞 news/index/{pageNum} GET 刪除該角色用戶的訪問權限
分頁查看某類新聞 news/{cate}/index/{pageNum} GET 同上
查詢所有新聞且是分頁的 news/search/{keyword}/{pageNum} GET 同上
爲該角色新添加符合它需求的url,然後分配權限給該角色。下面僅舉一個例子:
分頁查看所有作者爲當前用戶的新聞 news/index/{pageNum}/{author}

在這個url映射到的action處理方法中,該怎麼寫就怎麼寫,無需去管權限的問題,也就是說,在action代碼中,不要嘗試的去比較傳過來的author的值和session用戶中的值。因爲我的url權限控制模型已經幫你做了。至於具體如何做,這裏暫時不想談,但是可以說說原理,1.攔截器(是對每次action訪問的攔截,且在攔截器中能夠根據當前攔截到的url,找到綁定到它的url參數適配器,例如對於{author}參數的適配器,在該適配器中,大概思路是獲取author,然後跟當前session中的用戶作者比較,如果不同,就輸出權限不夠的信息。否則,chain一下就完事了。當然,適配器肯定是支持用戶自己擴展的。)

稍微補充點:我的url權限控制模型,url是支持變量的,例如news/index/{pageNum},這個url在真正進入角色權限表時,是會被轉成正則表達式news/index/\d+,分配給某角色之後,該角色訪問所有news/index/數字都會被通過。另外,該模型還能夠在定義url的時候,允許自己實現對url動態參數的賦值。例如news/index/{pageNum}可以給它綁定一個參數適配器,在該適配器中,可以給定值給pageNum,告訴模型,該值只能是什麼,例如只能是1,2,3等,甚至可以是是session中的值,總之,該模型本質上是一個攔截器,能夠獲取reqeust,response,out,session等重要的環境對象。

最後總結下:其實基於RBAC下的url權限控制模型是可靠的,一般而言,需要權限控制的數據都在訪問url中能夠獲取,那麼對於數據庫字段或者行級別的權限驗證,是能夠通過url參數適配器的方式去實現的。而且整個url權限控制模型又符合RESTful。

自家之言,歡迎拍磚。PS:暫時還在晚上我的這個url權限控制模型中。但是思路總體來說就是上面所講。

:D謝謝閱讀。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章