文中涉及的重要知識點有:
axios異步請求:axios-基於Promise的HTTP請求客戶耑
php-jwt庫:https://github.com/firebase/php-jwt
因此在閲讀這邊文章之前,請先了解以上知識點以及JWT的基本概念,這樣你會很快理解我們這篇文章中的實例代碼。
準備
用戶使用用戶名密碼來請求服務器 服務器進行驗证用戶的信息 服務器通過驗证發送給用戶一個token 客戶耑存儲token,並在每次請求時附送上這個token值 服務耑驗证token值,並返回數據
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>
javascript
<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'). = 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);
});
}
document.querySelector('#sub-btn'). = 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>document.querySelector('#logout'). = 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
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);
}