首頁 >後端開發 >PHP問題 >php如何設定權限令牌token

php如何設定權限令牌token

藏色散人
藏色散人原創
2020-08-20 10:13:002675瀏覽

php設定token的方法:1、定義取得Token的路由路徑;2、建立Service層;3、使用UserToken類別處理整個邏輯;4、在Model層建立User類別;5、在驗證器類別和異常類別會建立對應的驗證方法和異常處理。

php如何設定權限令牌token

推薦:《PHP影片教學

PHP_設定權限令牌Token

我們開發的後端API接口會對訪客有一個權限要求,例如一些包含私人資訊的接口,就需要訪問者請求接口的同時,傳遞一個提前已經發放給訪問者的Token。

這就像一個令牌一樣,只有訪客展示出來我們才會「透過放行」。

下面就記錄一下權限令牌的程式碼寫想法。


一、流程摘要

  • 定義取得Token的路由路徑,接受code參數(code來源:微信伺服器,登入系統基於微信系統)

  • 建立Service層,在這層建立Token基底類別和UserToken類別

  • UserToken類別處理整個邏輯:Token產生和傳回

  • 在Model層建立User類,負責使用者資料表的讀寫,供Service層的UserToken呼叫

  • 在驗證器類別和異常類建立對應的驗證方法與例外處理

  • 控制器->Service層->Model層傳回給Service層->Service層傳回值給控制器,整個流程完成Token令牌的編寫

二、具體說明

先定義好路由路徑:

Route::post(
    'api/:version/token/user',
    'api/:version.Token/getToken'
);

然後建立Token控制器,定義對應路由路徑的getToken方法:

public function getToken($code='') {
        (new TokenGet())->goCheck($code); // 验证器
        $token = (new UserToken($code))->get();
        return [
            'token' => $token
        ];
    }

在呼叫Service層之前,還要檢查一下傳遞過來的參數,於是定義TokenGet這個驗證器:

class TokenGet extends BaseValidate
{
    protected $rule = [
      'code' => 'require|isNotEmpty'
    ];

    protected $message = [
        'code' => '需要code才能获得Token!'
    ];
 }

回到Token控制器,驗證通過後,我們呼叫Service層定義的UserToken類別:

$token = (new UserToken($code))->get();复制代码

這裡討論一下Service層和Model層。我們普遍的理解是Service層是基於Model層的抽象封裝。

  • Model層只負責操作資料庫並回傳且回傳Service層
  • 然後Service層處理業務邏輯,最後傳回Controller層

但我覺得小專案的話,Service其實和Model就有點平級的意思,因為有些簡單的接口Model層直接對接Controller就可以了,只有相對複雜的接口,比如用戶權限,就可以再經過Service層分隔不同功能的代碼。

這樣的處理比較靈活,有大量確實很簡單的介面就不用過一次Service層了,這樣更像是走過過場而已,沒什麼意義了。

回到Service層的程式碼編寫,由於Token還會有不同的種類,所以先建立一個Token基類,裡麵包含一些通用的方法。然後就是給訪客回傳令牌的UserToken類別的編寫了。

由於是基於微信,我們需要三個資訊:code,appid,appsecret,然後透過建構子來給UserToken類別賦上初始值:

function __construct($code) {
    $this->code = $code;
    $this->wxAppID = config('wx.app_id');
    $this->wxAppSecret = config('wx.app_secret');
    $this->wxLoginUrl = sprintf(
        config('wx.login_url'),
        $this->wxAppID, $this->wxAppSecret, $this->code
    );
    }

然後把這三個放入微信提供的介面的參數位置,目的是取得一個完整的微信伺服器端的url,請求到我們需要的openid。

然後是透過發送網路請求的步驟就在此略過。微信伺服器會回傳包含openid的對象,判斷這個物件的值沒問題後,我們就開始產生令牌的步驟了,建立函數grantToken():#​​##

private function grantToken($openidObj) {

        // 取出openid
        $openid = $openidObj['openid'];
        
        // 通过Model层调用数据库,检查openid是否已经存在
        $user = UserModel::getByOpenID($openid);
        
        // 如果存在,不处理,反之则新增一条user记录
        if ($user) {
            $uid = $user->id;
        } else {
            // 不存在,生成一条数据,具体方法略过
            $uid = $this->newUser($openid); 
        }
        
        // 生成令牌,写入缓存(具体方法见下面的定义)
        $cachedValue = $this->prepareCacheValue($openidObj, $uid);
        $token = $this->saveToCache($cachedValue);
        
        // 令牌返回到调用者端
        return $token;
}

private function prepareCacheValue($openidObj, $uid) {
    $cachedValue = $openidObj;
    $cachedValue['uid'] = $uid;
    $cachedValue['scope'] = 16; // 权限值,自己定义
    return $cachedValue;
}
    
private function saveToCache($cachedValue) {
    $key = self::generateToken(); // 生成令牌的方法
    $value = json_encode($cachedValue);
    $tokenExpire = config('setting.token_expire'); // 设定的过期时间

    $request = cache($key, $value, $tokenExpire);
        if (!$request) {
            throw new TokenException([
            'msg' => '服务器缓存异常',
            'errorCode' => 10005
        ]);
    }
    return $key; // 返回令牌:token
}

可以看到,核心流程就是:

    拿到openid
  • 查看資料庫,檢查openid是否已經存在
  • #如果存在,不處理,反之則新增一則user記錄
  • 產生令牌,準備快取數據,寫入快取
  • 把令牌回到客戶端去
#其中

generateToken()這個方法詳細定義如下:

public static function generateToken() {
    $randomChars = getRandomChars(32); // 32个字符组成一组随机字符串
    $timestamp = $_SERVER['REQUEST_TIME_FLOAT'];  
    $salt = config('security.token_salt'); // salt 盐
    // 拼接三组字符串,进行MD5加密,然后返回
    return md5($randomChars.$timestamp.$salt);
}
    
function getRandomChars($length) {
    $str = null;
    $strPoll = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $max = strlen($strPoll) - 1;

    for ($i = 0; $i < $length; $i++) {
        $str .= $strPoll[rand(0, $max)];
    }
    return $str;
}

它的主要作用毫無疑問就是產生我們的需要的令牌-Token字串。值得一提的是由於

generateToken()在其他類型的Token裡也會用到,所以是放在Token基底類別裡的。

至此,只需要把產生的令牌再回到Controller就行了。

三、總結

令牌的編寫涉及到很多的流程,為了避免混亂,一定要注意把負責不同工作的程式碼分別定義在不同的方法裡。就像上面例子裡

grantToken()方法體現的那樣,這是個核心方法,包含所有流程,但是不同的具體流程又定義在其他方法裡,然後提供給grantToken()方法呼叫。

這樣做之後

grantToken()方法即使包含所有流程,但還是很容易閱讀。

以上是php如何設定權限令牌token的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn