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();
});
From WizNote