一、服務端不須要保存傳統會話信息,沒有跨域傳輸問題,減少服務器開銷。php
二、jwt構成簡單,佔用不多的字節,便於傳輸。html
三、json格式通用,不一樣語言之間均可以使用。前端
① 用戶使用用戶名密碼來請求服務器jquery
② 服務器進行驗證用戶的信息git
③ 服務器經過驗證發送給用戶一個tokengithub
④ 客戶端存儲token,並在每次請求時附送上這個token值web
⑤ 服務端驗證token值,並返回數據ajax
一、經過composer下載:數據庫
composer require firebase/php-jwt
二、github下載地址:https://github.com/firebase/php-jwtjson
三、百度雲下載地址:https://pan.baidu.com/s/1lpyz8oKf_CM-kOi7MGVoPg
提取碼:wyq0
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="showpage"> <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> </body> </html> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script> $('#sub-btn').on('click',function (e) { $.ajax({ type: 'post', url: './user.php?action=login', data: { username:$('#username').val(), password:$('#password').val(), }, dataType:'json', success: function (data, status, xhr) { alert(data.msg); if(data.code==200){ //將jwt存儲到本地 var jwt = xhr.getResponseHeader('Authorization'); localStorage.setItem("jwt", jwt); //跳轉登陸成功的頁面 window.location.href="./user.html"; } } }); }); </script>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你已成功登錄</h3> </body> </html> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script> $.ajax({ type: 'post', url: './user.php', headers: { 'Authorization': localStorage.getItem("jwt") }, data: {}, async: true, dataType: 'json', success: function (data, status, xhr) { if(data.code!=200){ //jwt驗證失敗 } //若是響應頭接收到了Authorization,則將本地jwt更新 if (xhr.getResponseHeader('Authorization')) { localStorage.setItem("jwt", jwt); } }, error: function () { alert('error'); } }); </script>
<?php /* 使用composer安裝php-jwt,接收到登陸用戶名和密碼後,PHP驗證用戶名和密碼是否正確 (實際開發中應該結合數據庫,從數據庫裏拿用戶名和密碼比對,本實例爲了演示只作簡單驗證), 若是用戶名和密碼準確無誤,那麼就簽發token,在token中,咱們能夠定義token的簽發者 、過時時間等等,並返回給前端。注意在簽發token時,咱們須要定義一個密鑰,這個密鑰是一個私鑰, 實際應用中是保密的不可告訴別人。 * */ require_once './php-jwt-master/src/JWT.php'; use \Firebase\JWT\JWT; define('KEY', '1gHuiop975cdashyex9Ud23ldsvm2Xq'); //密鑰 $action = isset($_GET['action']) ? $_GET['action'] : ''; if ($action == 'login') { if ($_SERVER['REQUEST_METHOD'] == 'POST') { $username = htmlentities($_POST['username']); $password = htmlentities($_POST['password']); $data = ['userid' => 1, 'username' => $username]; if ($username == 'demo' && $password == 'demo') { //用戶名和密碼正確,則簽發tokon $nowtime = time(); $token = [ 'iss' => 'http://www.helloweba.net', //簽發者 'aud' => $_SERVER['REMOTE_ADDR'], //jwt所面向的用戶 'iat' => $nowtime, //簽發時間 'exp' => $nowtime + 600, //過時時間-10min 'data' => $data ]; $jwt = JWT::encode($token, KEY); header("Authorization:$jwt"); $res = array('code' => 200, 'msg' => '登陸成功', 'data' => $data); } else { $res = array('code' => 300, 'msg' => '登陸失敗'); } } die(json_encode($res)); } else { $jwt = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : ''; if (empty($jwt)) { $res = array('code' => 301, 'msg' => 'You do not have permission to access.'); die(json_encode($res)); } try { JWT::$leeway = 60;//當前時間減去60,把時間留點餘地 $token = JWT::decode($jwt, KEY, ['HS256']); //HS256方式,這裏要和簽發的時候對應 } catch (Exception $exception) { $res = array('code' => 302, 'msg' => $exception->getMessage()); die(json_encode($res)); } // 疑似竊取用戶Token攻擊行爲:請求的客戶端ip已經改變, 拒絕請求 if ($token->aud !== $_SERVER['REMOTE_ADDR']) { $res['msg'] = "請求的客戶端ip已經改變, 拒絕請求"; } // token過了有效期, 可是在迴旋時間內, 靜默更新用戶token if ($token->exp < time()) { $token = (array)$token; $nowtime = time(); $token['iat'] = $nowtime; //簽發時間 $token['exp'] = $nowtime + 600; //過時時間-10min; $jwt = JWT::encode($token, KEY); header("Authorization:$jwt"); } $res = array('code' => 200, 'msg' => 'success'); die(json_encode($res)); }