php-jwt token驗證


例子:https://www.jianshu.com/p/a2efb2c8dcde

文中涉及的重要知識點有:

因此在閱讀這邊文章之前,請先了解以上知識點以及JWT的基本概念,這樣你會很快理解我們這篇文章中的實例代碼。

准備

在本站上篇文章《有關JWT(Json Web Token)的那些事》有介紹用戶登錄鑒權流程:

  • 用戶使用用戶名密碼來請求服務器
  • 服務器進行驗證用戶的信息
  • 服務器通過驗證發送給用戶一個token
  • 客戶端存儲token,並在每次請求時附送上這個token值
  • 服務端驗證token值,並返回數據

那么現在我們就按這個流程開始。

HTML

我們的HTML結構是這樣的:一個登錄表單,供用戶輸入用戶名和密碼,以及提交按鈕;一個是登錄成功后的顯示信息。

<div id="showpage" style="display: none"> <div class="form-group"> <label for="username">用戶名</label> <input type="text" class="form-control" id="username" placeholder="請輸入用戶名"> </div> <div class="form-group"> <label for="password">密碼</label> <input type="password" class="form-control" id="password" placeholder="請輸入密碼"> </div> <button type="submit" id="sub-btn" class="btn btn-default">登錄</button> <br/> <p class="bg-warning" style="padding: 10px;">演示用戶名和密碼都是<code>demo</code>。</p> </div> <div id="user" style="display: none"><p>歡迎<strong id="uname"></strong>,您已登錄,<a href="javascript:;" id="logout">退出>></a></p></div> 

詳細的代碼,可以下載demo源碼中查看,這里樣式我們使用的是Bootstrap3的經典樣式。

Javascript

前端Javascript異步請求,我們使用Axios庫,當然你也可以使用jQuery的Ajax方法。

首先引入axios庫:

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script> 

按照流程,1.提交登錄表單,發送用戶名和密碼到PHP后端,2.后端驗證成功后,會發送一個token給前端,3.前端再拿這個token去請求需要用戶權限訪問,4.后端驗證toen,鑒權,返回相應結果。下面的js代碼實現了1,3兩步。

<script>
    document.querySelector('#sub-btn').onclick = function() { let username = document.querySelector('#username').value; let password = document.querySelector('#password').value; var params = new URLSearchParams(); params.append('user', username); params.append('pass', password); axios.post( 'user.php?action=login', params ) .then((response) => { if (response.data.result === 'success') { // 本地存儲token localStorage.setItem('jwt', response.data.jwt); // 把token加入header里 axios.defaults.headers.common['X-token'] = response.data.jwt; axios.get('user.php').then(function(response) { if (response.data.result === 'success') { document.querySelector('#showpage').style.display = 'none'; document.querySelector('#user').style.display = 'block'; document.querySelector('#uname').innerHTML = response.data.info.data.username; } else { } }); } else { console.log(response.data.msg); } }) .catch(function (error) { console.log(error); }); } </script> 

很顯然,當登錄成功后,立馬使用本地存儲token,然后把這個token放在請求頭header里,再次去請求后端另一個用戶信息接口,如果成功了就顯示用戶信息。

如果要退出登錄,我們不需要再次去請求后端接口,直接前端清空本地存儲就OK了。

document.querySelector('#logout').onclick = function() { localStorage.removeItem('jwt'); document.querySelector('#showpage').style.display = 'block'; document.querySelector('#user').style.display = 'none'; } 

登錄成功后,當我們刷新頁面(再次請求需要登錄后才能訪問的頁面),需要進行判斷,判斷本地存儲中是否有token,如果有token,那就拿去給后端接口驗證下token是否合法,如果沒問題就顯示用戶相關信息,如果驗證失敗,那可能是token過去或者偽造的token等原因。

let jwt = localStorage.getItem('jwt'); if (jwt) { axios.defaults.headers.common['X-token'] = jwt; axios.get('user.php') .then(function (response) { if (response.data.result === 'success') { document.querySelector('#showpage').style.display = 'none'; document.querySelector('#user').style.display = 'block'; document.querySelector('#uname').innerHTML = response.data.info.data.username; } else { document.querySelector('#showpage').style.display = 'block'; console.log(response.data.msg); } }) .catch(function (error) { console.log(error); }); } else { document.querySelector('#showpage').style.display = 'block'; }

PHP

后端我們使用了一個專門的JWT庫:php-jwt

使用composer安裝php-jwt,接收到登錄用戶名和密碼后,PHP驗證用戶名和密碼是否正確(實際開發中應該結合數據庫,從數據庫里拿用戶名和密碼比對,本實例為了演示只做簡單驗證),如果用戶名和密碼准確無誤,那么就簽發token,在token中,我們可以定義token的簽發者、過期時間等等,並返回給前端。注意在簽發token時,我們需要定義一個密鑰,這個密鑰是一個私鑰,實際應用中是保密的不可告訴別人。

require 'vendor/autoload.php'; use \Firebase\JWT\JWT; define('KEY', '1gHuiop975cdashyex9Ud23ldsvm2Xq'); //密鑰 $res['result'] = 'failed'; $action = isset($_GET['action']) ? $_GET['action'] : ''; if ($action == 'login') { if ($_SERVER['REQUEST_METHOD'] == 'POST') { $username = htmlentities($_POST['user']); $password = htmlentities($_POST['pass']); if ($username == 'demo' && $password == 'demo') { //用戶名和密碼正確,則簽發tokon $nowtime = time(); $token = [ 'iss' => 'http://www.helloweba.net', //簽發者 'aud' => 'http://www.helloweba.net', //jwt所面向的用戶 'iat' => $nowtime, //簽發時間 'nbf' => $nowtime + 10, //在什么時間之后該jwt才可用 'exp' => $nowtime + 600, //過期時間-10min 'data' => [ 'userid' => 1, 'username' => $username ] ]; $jwt = JWT::encode($token, KEY); $res['result'] = 'success'; $res['jwt'] = $jwt; } else { $res['msg'] = '用戶名或密碼錯誤!'; } } echo json_encode($res); } else { $jwt = isset($_SERVER['HTTP_X_TOKEN']) ? $_SERVER['HTTP_X_TOKEN'] : ''; if (empty($jwt)) { $res['msg'] = 'You do not have permission to access.'; echo json_encode($res); exit; } try { JWT::$leeway = 60; $decoded = JWT::decode($jwt, KEY, ['HS256']); $arr = (array)$decoded; if ($arr['exp'] < time()) { $res['msg'] = '請重新登錄'; } else { $res['result'] = 'success'; $res['info'] = $arr; } } catch(Exception $e) { $res['msg'] = 'Token驗證失敗,請重新登錄'; } echo json_encode($res); }

用戶每次請求都要帶上后端簽發的token,后端獲取請求中的token,PHP中使用$_SERVER['HTTP_X_TOKEN']就可以獲取token值。這個X_TOKEN就是在我們前端的請求header頭信息中。

然后PHP拿到這個token后,解密分析token值,返回給前端即可。

結束語

以上就是整個JWT的實戰應用,我們可以看到,在用戶鑒權的過程中並沒有使用Session或者Cookie,服務端無需存儲用戶會話信息。只用了一個Token串,建立前后端的驗證的數據傳遞,實現了有效的登錄鑒權過程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM