## 權限管理主要由三部分組成:
1. 角色
2. 權限節點
3. 用戶
### 對應關系如下:
**權限節點綁定到角色上面,角色再與用戶綁定。**
*****
### **權限的驗證**
#### 操作菜單如何展示?
1. 首先用戶登陸
2. 根據用戶id查到他的角色
3. 再根據角色查到他可用的操作節點
4. 然后對于操作節點自身的分組id進行分組
5. 最后將這些分組通過json傳遞到前端或者后端進行拼接后展示給用戶。
6. 這樣就實現了,如果用戶沒有操作權限的話就不會展示用戶操作菜單。
*****
### 操作數據的驗證如何進行?
**每一次用戶點擊操作菜單的時候,對于整個操作詳情界面往往都有增刪改查4種操作。
對于每一種操作,都按照上面的角色用戶對應關系進行查詢。**
1. 拿到用戶的所的權限節點
2. 對于數據操作,首先判斷用戶權限節點中是否存在這些操作。
3. 有,則進行操作。
4. 沒有,則提示用戶沒有權限。
### **在thinkphp5中如何實現權限的驗證呢**?**
我用到了中間件來驗證用戶登陸情況,然后在后臺模塊的父控制器中,我根據用戶的登陸情況對用戶的可操作節點進行了判斷。
中間件代碼如下,更多的請看代碼庫中的代碼:[https://gitee.com/leihenshang/gossip_blog](https://gitee.com/leihenshang/gossip_blog)
```
<?php
namespace app\\http\\middleware;
use app\\common\\controller\\BackendBase;
class Check
{
public function handle($request, \\Closure $next)
{
$backendBaseObject = new BackendBase();
$backendBaseObject\->checkLoginStatus();
return $next($request);
}
}
```
權限驗證代碼:
```
<?php
namespace app\\common\\controller;
use app\\common\\model\\Permission;
use app\\common\\model\\RolePermissionRelation;
use app\\common\\model\\UserRoleRelation;
use app\\common\\model\\User;
use think\\Controller;
use think\\facade\\Cookie;
use think\\facade\\Request;
use think\\facade\\Session;
class BackendBase extends Controller
{
//超級管理員名稱
protected $superUserName = 'tangq';
//指定中間件
protected $middleware = \['Check'\];
//存儲用戶信息和用戶權限節點在當前類的子類中共享
protected $userinfo = null;
public static $userPermission = null;
//設置是否進行權限驗證,true驗證,false不驗證
public function checkPermission()
{
return false;
}
/\*\*
\* 獲取用戶信息
\* @param int $type 1為session 2 為Cookie
\* @return void
\*/
public function getUserInfo($type = 1)
{
if ($type === 1) {
$userinfo = Session::get('userinfo');
if (empty($userinfo) || $userinfo\['expire\_time'\] < time()) {
$userinfo = false;
}
return $userinfo;
} else {
$userinfo = Cookie::get('userinfo');
$userinfo = json\_decode($userinfo, true);
if (empty($userinfo) || $userinfo\['expire\_time'\] < time()) {
$userinfo = false;
}
return $userinfo;
}
}
/\*\*
\* 檢查用戶登陸狀態
\*/
public function checkLoginStatus()
{
//獲取用戶登陸信息
$this\->userinfo = $this\->getUserInfo();
if($this\->userinfo === false){
// return returnData(false,'獲取用戶信息失敗');
$this\->error('重新登陸','index/user/index','',1);
}
//檢查用戶是否在其他地方登錄
if (Request::controller() == 'MyCenter') {
if (false === User::checkOnlyLogin($this\->userinfo)) {
User::clearUserinfo();
$this\->error('您可能在其他地方登錄,請重新登錄嘗試', 'index/user/index', '', 1);
}
}
if (true === $this\->checkPermission()) {
//后臺頁面權限控制
if (Request::controller() == 'MyCenter') {
if (!$this\->userinfo) {
$this\->error('用戶信息錯誤,請重新登陸', 'index/user/index', '', 1);
}
//根據用戶信息獲取當前用戶全部可訪問節點
$userPermission = $this\->getPermissionNode($this\->userinfo);
//獲取請求路徑信息
$pathInfo = $this\->getUserRequestPath($userPermission);
//判斷權限驗證結果
if ($pathInfo === false) {
$this\->error('沒有訪問權限', 'index/index/index', '', 1);
}
} else {
//定義json返回結構
$data = \['success' => false, 'msg' => '沒有訪問權限', 'data' => \[\], 'status' => 200\];
//沒有找到用戶信息的情況
if (!$this\->userinfo) {
//指定json header頭
header('Content-type:text/json');
echo json\_encode($data);
die;
}
//判斷節點權限
$userPermission = $this\->getPermissionNode($this\->userinfo);
//獲取請求路徑信息
$pathInfo = $this\->getUserRequestPath($userPermission);
//判斷權限驗證結果
if ($pathInfo === false) {
//指定json header頭
header('Content-type:text/json');
echo json\_encode($data);
die;
}
}
} else {
$this\->userinfo\->username = 'tangq';
$userPermission = $this\->getPermissionNode($this\->userinfo);
}
//存儲用戶可訪問節點
self::$userPermission = $userPermission;
// $this->userPermission = $userPermission;
//為模板寫入用戶信息
$this\->assign('userinfo', $this\->userinfo);
//為模板寫入后臺管理菜單列表
$this\->assign('menuList', $this\->getMenu($this\->userinfo));
}
/\*\*
\* 獲取用戶真實請求路徑,返回用戶請求的路徑的數組
\* @param array $userPermission 用戶節點信息一維數組
\* @return void
\*/
public function getUserRequestPath($userPermission = \[\])
{
if (empty($userPermission)) {
return false;
}
$pathInfo = \[Request::path()\];
$routeInfo = Request::routeInfo();
if (!empty($routeInfo)) {
$pathInfo\[\] = $routeInfo\['route'\];
}
//判斷節點權限
$res = false;
foreach ($pathInfo as $pathValue) {
if (in\_array($pathValue, $userPermission)) {
$res = true;
break;
}
}
//返回結果
return $res;
}
/\*\*
\* 根據用戶信息獲取權限節點
\*
\* @param object $userId
\* @param int $nodeType 節點類型 0 全部,1分組,2頁面,3功能性節點
\* @return void
\*/
public function getPermissionNode($userInfo, $nodeType = 0)
{
if (!$userInfo) {
return \[\];
}
//超級用戶返回所有權限節點
if ($userInfo\->username === $this\->superUserName) {
$userPermissionUrl = Permission::column('node\_url');
return $userPermissionUrl;
}
//根據用戶id獲取用戶屬于哪個角色
$userRoleId = UserRoleRelation::where('user\_id', $userInfo\->id)->column('role\_id');
if (!$userRoleId) {
return \[\];
}
//獲取用戶所屬角色的權限節點id
$userPermissionId = RolePermissionRelation::where('role\_id', 'in', $userRoleId)->where('is\_deleted', 0)->column('permission\_id');
//獲取權限節點url
$userPermissionUrl = Permission::where('id', 'in', $userPermissionId)->where('is\_deleted', 0)->column('node\_url');
if ($nodeType != 0) {
$userPermissionUrl\->where('type', $nodeType);
}
return $userPermissionUrl;
}
/\*\*
\* 獲取后臺管理菜單列表
\*
\* @param string $userinfo 用戶信息
\*
\* @return array
\*/
public function getMenu($userinfo)
{
$arr = \[\];
if (!empty($userinfo)) {
if ($userinfo\->username == $this\->superUserName) {
//獲取用戶用戶的菜單列表
$resMenu = Permission::field('id,name,node\_url,p\_id,is\_expand')->where('type', 'in', \[0, 1\])->select()->toArray();
} else {
//獲取用戶屬于哪個角色
$userRole = UserRoleRelation::where('user\_id', $userinfo\->id)->column('role\_id');
if (!$userRole) {
$this\->error('沒有指定用戶的角色', '', '', 1);
}
//獲取用戶所屬角色的權限節點
$userPermission = RolePermissionRelation::where('role\_id', 'in', $userRole)->where('is\_deleted', 0)->column('permission\_id');
//獲取權限節點
$resMenu = Permission::field('id,name,node\_url,p\_id,is\_expand')->where('type', 'in', \[0, 1\])->where('is\_deleted', 0)->where('id', 'in', $userPermission)->select()->toArray();
}
} else {
return \[\];
}
//處理url以及設置子節點
foreach ($resMenu as $value) {
$value\['node\_url'\] = $value\['node\_url'\] == '#' ? 'javascript:;' : $value\['node\_url'\]; //處理url
if ($value\['node\_url'\] != 'javascript:;') {
$value\['node\_url'\] = mb\_substr($value\['node\_url'\], 0, 1) == '/' ? $value\['node\_url'\] : '/' . $value\['node\_url'\];
}
$value\['child'\] = \[\];
$arr\[$value\['id'\]\] = $value;
}
//生成父子節點
foreach ($resMenu as $key => $value) {
if (isset($arr\[$value\['p\_id'\]\])) {
$arr\[$value\['p\_id'\]\]\['child'\]\[\] = $value;
unset($arr\[$value\['id'\]\]);
}
}
return $arr;
}
}
```