使用JWT(Json Web Token)實現登陸認證

今天咱們來結合實例給你們講述JWT(Json Web Token)的實戰應用,就是如何使用前端Axios與後端PHP實現用戶登陸鑑權認證的過程。javascript

文中涉及的重要知識點:

axios異步請求:axios-基於Promise的HTTP請求客戶端
php-jwt庫:https://github.com/firebase/p...
HTML5相關知識
所以在閱讀這邊文章以前,請先了解以上知識點以及JWT的基本概念,這樣你會很快理解咱們這篇文章中的實例代碼。php

準備

用戶登陸鑑權流程:css

用戶使用用戶名密碼來請求服務器
服務器進行驗證用戶的信息
服務器經過驗證發送給用戶一個token
客戶端存儲token,並在每次請求時附送上這個token值
服務端驗證token值,並返回數據
那麼如今咱們就按這個流程開始。html

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的經典樣式。java

Javascript

前端Javascript異步請求,咱們使用Axios庫,固然你也可使用jQuery的Ajax方法。ios

首先引入axios庫:git

<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兩步。github

<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裏,再次去請求後端另外一個用戶信息接口,若是成功了就顯示用戶信息。web

若是要退出登陸,咱們不須要再次去請求後端接口,直接前端清空本地存儲就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串,創建先後端的驗證的數據傳遞,實現了有效的登陸鑑權過程。

在線演示demo:https://www.helloweba.net/dem...

相關文章
相關標籤/搜索