ThinkCMF中的權限是以后台菜單為基礎來進行設置的(menu table),即如果你需要一個自定義的權限,那么你需要在后台菜單里添加一項菜單,
然后在角色管理里可以針對角色進行授權


而現在遇到一個需求:管理員可以自行選擇哪些用戶可以查看某些分類(除了幾個指定分類外其他分類都是公開的)
因為我這里的用戶其實就是相當於不同的管理員,所以我就直接把權限問題整合到了現有的“角色授權”功能里
因為(只有幾個分類需要授權,所以我將這些分類都移到一個一級分類里"內網登錄"
然后在后台角色授權(
RbacController
)里直接對該分類及子分類進行處理(該分類ID保存在配置文件中
AUTHORIZE_CATID
)
\application\Admin\Controller\RbacController.class.php
中添加了對分類進行授權的功能
/** * 角色授權 */ public function authorize() { $this->auth_access_model = D("Common/AuthAccess"); //角色ID $roleid = intval(I("get.id")); if (!$roleid) { $this->error("參數錯誤!"); } import("Tree"); $menu = new \Tree(); $menu->icon = array('│ ', '├─ ', '└─ '); $menu->nbsp = ' '; $result = $this->initMenu(); $newmenus=array(); $priv_data=$this->auth_access_model->where(array("role_id"=>$roleid))->getField("rule_name",true);//獲取權限表數據 foreach ($result as $m){ $newmenus[$m['id']]=$m; } foreach ($result as $n => $t) { $result[$n]['checked'] = ($this->_is_checked($t, $roleid, $priv_data)) ? ' checked' : ''; $result[$n]['level'] = $this->_get_level($t['id'], $newmenus); $result[$n]['parentid_node'] = ($t['parentid']) ? ' class="child-of-node-' . $t['parentid'] . '"' : ''; } $str = "<tr id='node-\$id' \$parentid_node> <td style='padding-left:30px;'>\$spacer<input type='checkbox' name='menuid[]' value='\$id' level='\$level' \$checked onclick='javascript:checknode(this);'> \$name</td> </tr>"; $menu->init($result); $categorys = $menu->get_tree(0, $str); //需要授權的分類列表 $categorys.= $this->_authorize_cat($priv_data);
$this->assign("categorys", $categorys); $this->assign("roleid", $roleid); $this->display(); } /** * 角色授權 */ public function authorize_post() { $this->auth_access_model = D("Common/AuthAccess"); if (IS_POST) { $roleid = intval(I("post.roleid")); if(!$roleid){ $this->error("需要授權的角色不存在!"); } if (is_array($_POST['menuid']) && count($_POST['menuid'])>0) { $menu_model=M("Menu"); $auth_rule_model=M("AuthRule"); $this->_authorize_post_cat($_POST['catid'],$roleid);
$this->auth_access_model->where(array("role_id"=>$roleid,'type'=>'admin_url'))->delete(); foreach ($_POST['menuid'] as $menuid) { $menu=$menu_model->where(array("id"=>$menuid))->field("app,model,action")->find(); if($menu){ $app=$menu['app']; $model=$menu['model']; $action=$menu['action']; $name=strtolower("$app/$model/$action"); $this->auth_access_model->add(array("role_id"=>$roleid,"rule_name"=>$name,'type'=>'admin_url')); } } $this->success("授權成功!", U("Rbac/index")); }else{ //當沒有數據時,清除當前角色授權 $this->auth_access_model->where(array("role_id" => $roleid))->delete(); $this->error("沒有接收到數據,執行清除授權成功!"); } } } /** * 角色授權-支持指定分類 * @Author HTL * @DateTime 2016-08-10T10:20:01+0800 * @param string $priv_data[auth_access table data] * @return [type] [description] */ function _authorize_cat($priv_data) { $cat_id = intval(C("AUTHORIZE_CATID"));//from config.php ,該分類必須是一級分類 if($cat_id<=0) return; $cats = M("Terms")->where("status=1 and path like '%0-$cat_id%'")->order("parent,listorder,term_id")->getField("term_id as id,name,parent,path",true); if(!cats || count($cats)<=0) return; $cat_html = "";//生成的html //根據不同level生成不同層級效果 $level_spacer = array('',' ├─' ,' │ ├─ ',' │ │ └─ ' ); $str = "<tr id='cat-#id#' #parentid_node#> <td style='padding-left:30px;'>#spacer#<input type='checkbox' name='catid[]' value='#id#' level='#level#' #checked# onclick='javascript:checknode(this);'> #name#</td> </tr>"; foreach ($cats as $key => $value) { $checked = in_array($value['id'],$priv_data)?"checked":""; //權限中是否已經存在該分類id $level = count(explode('-',$value['path']))-2; //減2是因為:要去掉數據庫中的0-不算和explode方法是從1開始的 $parentid_node = ($value['parent']) ? ' class="child-of-cat-' . $value['parent'] . '"' : '';//父類 $_str = str_replace('#id#',$value['id'],$str); $_str = str_replace("#spacer#",$level_spacer[$level],$_str); $_str = str_replace("#level#",$level,$_str); $_str = str_replace("#checked#",$checked,$_str); $_str = str_replace("#parentid_node#",$parentid_node,$_str); $_str = str_replace("#name#",$value['name'],$_str); $cat_html .= $_str; } return '<tr><td><br></td></tr>'.$cat_html; } /** * 將選擇的分類保存到權限表中 * @Author HTL * @DateTime 2016-08-10T11:45:48+0800 * @param [type] $catids [post catids] * @param [type] $roleid [current user roleid] * @return [type] [description] */ function _authorize_post_cat($catids,$roleid) { if(!$catids || count($catids)<=0 || $roleid<=0) return; //使用單獨的type(cat_url)進行區分 $this->auth_access_model->where(array("role_id"=>$roleid,'type'=>'cat_url'))->delete(); foreach ($catids as $catid) { $this->auth_access_model->add(array("role_id"=>$roleid,"rule_name"=>$catid,'type'=>'cat_url')); } }
\data\conf\config.php
中定義一個配置項,並指定一級分類ID
<?php return array ( 'AUTHORIZE_CATID' => 30,/*需要授權才能訪問的一級分類ID(自動包括所有子分類),必須是一級分類*/ );?>
修改后的角色授權頁面
保存后的數據庫信息(cmf_auth_access)

2016-08-11 update:
之前沒有考慮一個問題是:在添加或編輯文章時如果管理員對文章同時選擇了有權限的分類和沒有權限的分類,那這種情況權限不就沒有用了嗎?
下面是我的解決辦法,即在保存文章時去判斷是否同時選擇了有權限和無權限的分類,如果有則不能進行保存操作,
\application\Portal\Controller\AdminPostController.class.php
/** * 在顯示模板之前調用此方法 $this->get_authority_cats();,用於前端處理 * 獲取需要權限的所有分類 * 用於防止管理員同時選擇有權限的分類和沒有權限的分類 * @AuthorHTL * @DateTime 2016-08-11T11:01:49+0800 * @param boolean $is_view [是否在頁面上展示,default=true] * @return [type] [description] */ function get_authority_cats($is_view = true) { $cat_id = intval(C("AUTHORIZE_CATID"));//需要權限的一級 if($cat_id<=0) return; $cats = M("Terms")->where("status=1 and path like '%0-$cat_id%'")->order("parent,listorder,term_id")->getField("term_id",true); if($is_view){ $this->assign("authrize_cats",implode(",",$cats)); } else{ return $cats; } } /** * 在保存文章之前調用此方法 $this->check_cats($_POST['term']),防止前端檢測未執行或被人為繞過 * 檢查文章的分類是否同時包含了有權限的和無權限的 * 要么選擇的全部是有權限的 * 要么選擇的全部是無權限的 * 不能混合選擇 * @AuthorHTL * @DateTime 2016-08-11T11:09:07+0800 * @param [type] $_POST [description] * @return [type] [description] */ function check_cats($post_cats) { if(!$post_cats || count($post_cats)<=0) return; $first_result = ture; $auth_cats = $this->get_authority_cats(false); if(!$auth_cats || count($auth_cats)<=0) return; foreach ($post_cats as $i=>$mterm_id){ //以首行的結果做比較基礎 if($i<=0){ $first_result = false;//in_array($mterm_id, $auth_cats); } //如果跟首次的不同則說明包含有權限和沒有權限的分類 else if($first_result != in_array($mterm_id,$auth_cats)){ $this->error("不能同時選擇有權限的欄目和無權限的欄目!"); return false; } } }
前端頁面的腳本處理
/** * 檢查文章的分類是否同時包含了有權限的和無權限的 * 要么選擇的全部是有權限的 * 要么選擇的全部是無權限的 * 不能混合選擇 * @AuthorHTL * @DateTime 2016-08-11T10:41:05+0800 * @return {[type]} [description] */ function check_cat() { var _term_vals = $("#term").val()//選擇的欄目列表 ,first_result = true//default value ,auth_cats = ',{$authrize_cats},';//有權限的欄目 //只有選擇了一個分類或沒有權限分類 if(_term_vals.length<=1 || auth_cats.length<=2) return true; for(i in _term_vals){ //以首行的結果做比較基礎 if(i<=0){ first_result = auth_cats.indexOf(","+_term_vals[i]+",")>=0; } //如果跟首次的不同則說明包含有權限和沒有權限的分類 else if(first_result !== auth_cats.indexOf(","+_term_vals[i]+",")>=0){ alert("不能同時選擇有權限的欄目和無權限的欄目!"); return false; } } return true; } //提交前先檢測 $(".J_ajax_submit_btn").click(function () { return check_cat(); });