posts - 193,  comments - 520,  trackbacks - 0
          一開始我把控制數據權限寫在業務里,以訂單管理為例,先討論一個最簡單的情況。管理員可以看所有的訂單,而用戶只能看自己的訂單。這里的管理員是一個角色。我會這么寫(一些次要代碼都省略了):

          ???List?getOrders(String?userId){
          ?????????????String?sql;
          ?????????????Role?role
          =orgService.getRoleForUser(userId);
          ?????????????
          if(("admin").equals(role.getName()))
          ???????????????????sql
          ="select?*?from?order";
          ?????????????
          else
          ???????????????????sql
          ="select?*?from?order?where?author="+userId;
          ?????????????Object?o
          =excuteSql(sql);
          ?????????????
          return?excute(o);
          ????????}

          恩,不錯,很好的完成了權限控制。過了沒多久,公司發展了,老板增加了人手,老板發話了,我要設置區域管理員分管不同區域的訂單。管理員分為北京地區管理員,上海地區管理員,其他地區管理員和總管理員。怎么辦?修改代碼吧
          ????List?getOrders(String?userId){
          ?????????????String?sql;
          ?????????????Role?role
          =orgService.getRoleForUser(userId);
          ?????????????
          if(("admin").equals(role.getName()))
          ??????????????????sql
          ="select?*?from?order";
          ?????????????
          else?if("bjadmin").equals(role.getName()))
          ?????????????????????????sql
          ="select?*?from?order?where?area='beijing'";
          ?????????????
          else?if("shadmin").equals(role.getName()))
          ?????????????????????????sql
          ="select?*?from?order?where?area='shanghai'";
          ?????????????
          else?if("qtadmin").equals(role.getName()))
          ?????????????????????????sql
          ="select?*?from?order?where?area='qita'";
          ?????????????
          else
          ???????????????????sql
          ="select?*?from?order?where?author="+userId;
          ?????????????Object?o
          =excuteSql(sql);
          ?????????????
          return?excute(o);
          ????????}

          恩恩,這就搞定了,可怎么也感覺不爽,也許該做點什么。一堆if/else權限判斷讓人心煩,再寫個類把這些sql管理起來好了,那就動手吧
          ??public?class?SqlManager{
          ??????????String?getSql(String?userId){
          ??????????????????String?sql;
          ??????????Role?role
          =orgService.getRoleForUser(userId);
          ??????????
          if(("admin").equals(role.getName()))
          ??????????????sql
          ="select?*?from?order";
          ??????????
          else?if("bjadmin").equals(role.getName()))
          ???????????????????sql
          ="select?*?from?order?where?area='beijing'";
          ??????????
          else?if("shadmin").equals(role.getName()))
          ???????????????????sql
          ="select?*?from?order?where?area='shanghai'";
          ??????????
          else?if("qtadmin").equals(role.getName()))
          ???????????????????sql
          ="select?*?from?order?where?area='qita'";
          ??????????
          else
          ????????????sql
          ="select?*?from?order?where?author="+userId;
          ??????????
          return?sql;
          ??????????}
          ??}

          這樣把權限判斷移到SqlManager里,業務代碼就清爽了很多,再增加管理員就修改SqlManager好了
          ????List?getOrders(String?userId){
          ?????????????String?sql
          =sqlManager.getSql(userId);
          ?????????????Object?o
          =excuteSql(sql);
          ?????????????
          return?excute(o);
          ????????}

          呵呵,看起來還不錯。但是等等,我們的業務方法為什么需要userId這個參數呢,是啊是啊,權限判斷用到了它,但是那和我業務又有什么關系呢,不爽。現在AOP不是很流行嗎,你不用AOP怎么能說明你技術高呢?快用吧快用吧,用不著也要想著方法用。
          業務方法簡化為
          ????List?getOrders(){
          ?????????????String?sql
          ="";
          ?????????????Object?o
          =excuteSql(sql);
          ?????????????
          return?excute(o);
          ????????}

          對excuteSql方法我們來AOP一下,注入權限判斷過的sql.嘿嘿,技術水平又一次得到了顯現。業務方法是簡單了,可我的SqlManager倒是復雜了,還是很不幸福。咋辦?用個配置文件吧,hibernate不是老鼓勵我們把sql寫在配置文件里嗎?
          ????<xml>
          ????????<sql?role
          ="admin">select?*?from?order</sql>
          ????????<sql?role
          ="bjadmin">select?*?from?order?where?area='beijing'</sql>
          ????????<sql?role
          ="shadmin">select?*?from?order?where?area='shanghai'</sql>
          ????????<sql?role
          ="qtadmin">select?*?from?order?where?area='qita'</sql>
          ????????<sql?role
          ="none">select?*?from?order?where?author=?</sql>
          ????</xml>

          這樣SqlManager就可以把行數縮小了,就可以敏捷一點了。
          ????public?class?SqlManager{
          ??????????String?getSql(String?userId){
          ??????????????????String?sql;
          ??????????Role?role
          =orgService.getRoleForUser(userId);
          ??????????sql
          =getSqlfromXml(role.getName());
          ??????????
          return?sql;
          ??????????}
          ??????????
          ??????????String?getSqlfromXml(String?rolename){
          ??????????????????.
          ??????????}
          ??}

          以后再增加權限連類都不用修改了,改xml好了。等等,你是不是把問題太簡單化了。現在不僅僅是訂單,貨物也要這么分區域管理。
          不錯,我們應該想著通用一下了。這樣,把SqlManager抽象一下
          ????????String?abstract?getSqlfromXml(String?rolename);

          然后做幾個子類好了 OrderSqlManager, GoodsSqlManager .
          可是,哥們,書上說,要面向接口編程,你這樣不太好吧。沒事,再接口一下:
          ???public?interface?SqlManagerInterface{
          ???????????String?getSql(String?userId);
          ???}

          還是沒法用啊。也許現在可以看看acegi的provider機制了,把這一大堆SqlManager全部作為provider,根據不同的模塊選擇不同的provider,統一攔截excuteSql方法,生成不同的sql到數據庫執行。xml不爽?db也可以。然后,再然后呢?改你的類名,重構,和acegi整合一下。
          呵呵,完全是個人的一些想法,希望多批評提提意見。我想表達的意思是:也許把數據權限再抽象一些,以組件的形式來減少侵入是可以做到的。

          http://www.aygfsteel.com/ronghao 榮浩原創,轉載請注明出處:)
          posted on 2007-03-23 18:35 ronghao 閱讀(6721) 評論(6)  編輯  收藏 所屬分類: 權限相關

          FeedBack:
          # re: 對數據權限控制的實驗
          2007-03-24 23:21 | 龍卷風驛站
          比較適合講知識,文筆不錯,贊一個  回復  更多評論
            
          # re: 對數據權限控制的實驗[未登錄]
          2007-03-26 10:15 | 阿蜜果
          你的權限篇寫得不錯,up!  回復  更多評論
            
          # re: 對數據權限控制的實驗
          2007-03-29 10:52 | jerome
          講的不錯,淺顯易懂,深有收獲啊  回復  更多評論
            
          # re: 對數據權限控制的實驗[未登錄]
          2007-10-11 15:29 | MagicYang
          我看到第3段代碼就聯想到:
          1、先把if/else if換成switch語句;
          2、再用多態替換switch語句;
          用戶接口:
          public interface User{
          public abstract List getOrders();
          }

          普通用戶:
          public abstract class User implements User{
          public List getOrders(String userId){
          sql="select * from order where author="+userId;
          Object o=excuteSql(sql);
          return execute(o);
          }
          }

          管理員:
          public abstract class Administrator implements User{
          public List getOrders(String adminId){
          sql="select * from order where area=" + getAreaByAdmin();
          Object o=excuteSql(sql);
          return execute(o);
          }

          protected abstract String getAreaByAdmin();
          }

          北京地區管理員:
          public class BjAdministractor extends Administractor{
          protected String getAreaByAdmin(){
          return "beijing";
          }
          }

          除了訂單,如果貨物也要加入區域管理的話- -!,只需要在普通用戶和管理員兩個抽象類中加入相關的抽象方法,具體的區域管理員里各自實現他們就行了。我的方法是不是很土。。。  回復  更多評論
            
          # re: 對數據權限控制的實驗[未登錄]
          2007-10-11 15:34 | MagicYang
          e...好象User類和User接口重名了  回復  更多評論
            
          # re: 對數據權限控制的實驗[未登錄]
          2007-10-11 15:39 | MagicYang
          以上只是基于你的數據權限控制實驗的所做重構,一般來說不傾向這么做,只把sql的area查詢條件作參數傳遞就行了,你不用這么多xml,我也不用這么多子類。。。不過我覺得這只是你的一個實驗例子而已對吧  回復  更多評論
            
          <2007年3月>
          25262728123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          關注工作流和企業業務流程改進。現就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

          常用鏈接

          留言簿(38)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          常去的網站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 渝中区| 卓尼县| 敖汉旗| 东明县| 太仆寺旗| 平阴县| 翁牛特旗| 万山特区| 曲靖市| 阜康市| 兰溪市| 宁明县| 蒲城县| 东城区| 上饶市| 霍邱县| 古丈县| 富民县| 信阳市| 宝丰县| 鱼台县| 平顶山市| 商河县| 闸北区| 克拉玛依市| 夏邑县| 宁乡县| 凌源市| 兰坪| 商洛市| 金溪县| 惠水县| 平度市| 太白县| 青田县| 芦山县| 大埔区| 商都县| 建瓯市| 绥宁县| 湘潭县|