php+redis實現用戶權限判斷
最近剛好有同事在寫一個基於redis的權限模塊.最開始我們這個模塊使用數據庫保存權限,但是同事說如果用戶請求大的,每一次請求都要訪問數據庫的數據庫可能會扛不住.不如把權限放到redis裏面.我redis寫的多,就幫他寫出這個代碼.
對應的代碼中有三個文件,,兩個代碼文件,一個測試文件
===
redisBase
首先我寫了一個redis連接的,這個是把之前寫的幾個redis類的連接方法抽取出來了,放在構造函數,再扔到一個trait裏面,這樣之後寫redis的模塊,直接放這個trait就好.如果有多個連接池或者遠程redis服務器,就修改這個trait.
/**
* 通用的redisbase trait 鏈接數據庫
* @author bapijun
*
*/
trait redisBase {
/*
* 當前的redis
*/
private $redis;
function __construct($redis = [])
{
//$this->redis = $redis;
$this->redis = new \Redis();
$this->redis->connect('127.0.0.1');
}
}
獲取權限函數
首先獲取從其他地方(我們這個項目是mysql)獲取權限.
/**
* 獲取用戶的權限
* @param callable $authorizeFunctiuon 回調函數,用來讀取用戶的權限
* @param $id 用戶id
* @return 用戶的權限
*/
public function getAuthorize(callable $authorizeFunctiuon, $id)
{
return $authorizeFunctiuon($id);
}
這裏我用了閉包函數作爲,每一次用閉包函數作爲從數據庫還是其他什麼地方獲取的函數方法.在類裏面用成員$authorizeFunctiuon,保存這個閉包函數.而這個閉包函數是獲取用戶id,當然你也可以寫成token.
爲什麼寫閉包函數,因爲我們不知道到底是從什麼環境裏面得到用戶權限.所以直接把這個獲取方法寫成參數的形式.
我在這裏類裏面還寫了另一個函數setAuthorzeFunction,保存權限函數,這樣這個閉包方法寫一次就好,之後直接就可以調用.
權限判斷
/**
* 權限判斷函數
* @param [string] $checkAuthorize 需要判斷的權限
* @param [int] $id 用戶id
* @param [callback] $authorizeFunctiuon 緩存中miss後獲取權限的方法
* @return [bool] 是否
*/
public function checkAdminAuthorize($checkAuthorize, $id, $authorizeFunctiuon = null)
{
if ($authorizeFunctiuon != null) {
$this->authorizeFunctiuon = $authorizeFunctiuon;
}
$authorizeList = $this->redis->get('member:authorize:' . $id);
if (empty($authorizeList)) {
//如果不存在需要去讀數據庫
$authorizeList = $this->saveAuthorize($this->authorizeFunctiuon, $id);
}
$authorizeList = explode(',', $authorizeList);
return in_array($checkAuthorize, $authorizeList) ? true : false;
}
這是我寫的權限判斷函數,$checkAuthorize, 這裏的邏輯就比較簡單了,首先判斷是否導入新的獲取權限的方法.之後檢查當前用戶的redis中是否權限,如果沒有就去閉包方法獲取權限,並保存到緩存中.
/**
* 獲取用戶權限並保存到緩存中
* @param callable $authorizeFunctiuon 回調函數,用來讀取用戶的權限
* @param $id 用戶id
* @return redis返回值
*/
private function saveAuthorize(callable $authorizeFunctiuon, $id)
{
$authorize = $this->getAuthorize($authorizeFunctiuon, $id);
$this->redis->set('member:authorize:' . $id , $authorize, Array('nx', 'ex'=>24*60*60));//設置保存事件
return $authorize;
}
最後是判斷權限是否成立.這個方法可以自己修改,我這裏是我們項目裏面用字符串中是否存在權限判斷.
使用方法
$redis = new RedisAuth();
$id = 1;
$config = ['database_type' => 'mysql',
'database_name' => '*****',
'server' => 'localhost',
'port' => 3306,
'username' => 'user',
'password' => '*********',
'charset' => 'utf8',
'option' => array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)];
$redis->setAuthorzeFunction(function ($id) use ($config) {
$db = new Medoo($config);
return $db->get('tb_admin_department', 'authorizelist', ['tbid' => $id]);
});
echo $redis->checkAdminAuthorize('order.browse', 1);
其實沒什麼好說的,主要是看看閉包方法這麼寫,這裏使用use獲取外部的配置.然後在mysql中獲取.我這裏用了一個輕量級的數據庫訪問類