This is an explanation of the video content.
 用技术延续对ACG的热爱
63

 |   | 

PHP使用Composer安装JWT并调用生成token

了解与简单案例

第一步,安装

composer require firebase/php-jwt

第二步,调用并输出

<?php
require __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$key = 'w3ee7sauja91701h'; //这里填写你自己设置的密钥
$payload = [
    'iss' => 'http://buaoye8.com', //jwt签发者 这个地方你可以自定义,这里我写的我们站点
    'aud' => 'http://buaoye8.com', //接收jwt的一方 这个地方你可以自定义,这里我写的我们站点
    "exp"=>time()+3600*2,// jwt的过期时间,过期时间必须要大于签发时间  时间戳+3600s*2   [时间戳是自1970 年1 月1 日(00:00:00 GMT)以来的秒数。]
    'iat' => time(), // jwt的签发时间
    'nbf' => time() // 定义在什么时间之前,某个时间点后才能访问
];


$jwt = JWT::encode($payload, $key, 'HS256');  //encode加码
$decoded = JWT::decode($jwt, new Key($key, 'HS256')); //decode解码

echo "加密后得到的JWT为";
print_r($jwt);

echo "<br/><br/>解密JWT得到的签证信息为";
print_r($decoded); //打印解码

$decoded_array = (array) $decoded;
// 转化为数组输出
echo "<br/><br/>转化为数组输出";
var_dump((array) $decoded);

JWT::$leeway = 60; // $leeway in seconds
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));

实战一:token在服务端封装后的生成与验证实例

该实战分别由三个部分组成:核心程序jwt.php,token生成程序generate.php,和token解析程序parse.php

jwt.php

<?php
require __DIR__ . '/vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class JwtAuth
{
    private $key = 'w3ee7sauja91701h'; //这里填写你自己设置的密钥

    //加密
    //返回token
    public function generate($userId)
    {
        $payload = [
            'iss' => 'http://buaoye8.com', //jwt签发者 这个地方你可以自定义,这里我写的我们站点
            'aud' => 'http://buaoye8.com', //接收jwt的一方 这个地方你可以自定义,这里我写的我们站点
            "exp" => time() + 3600 * 2, // jwt的过期时间,过期时间必须要大于签发时间  时间戳+3600s*2   [时间戳是自1970 年1 月1 日(00:00:00 GMT)以来的秒数。]
            'iat' => time(), // jwt的签发时间
            'nbf' => time(), // 定义在什么时间之前,某个时间点后才能访问
            'data' => [
                'userId' => $userId, //账号ID
                // '...'=>.....
            ]
        ];

        $token = JWT::encode($payload, $this->key, 'HS256');  //encode加码
        return $token;
    }

    public function parse($token)
    {
        $decoded = JWT::decode($token, new Key($this->key, 'HS256')); //decode解码

        //如果用户的token解密后的一些数据(比如账户ID)和前端登录保存在cookie里的账户ID是吻合的,那么就说明是本人
        return $decoded->data->userId;
    }
}

generate.php

require_once "./jwt.php";

$jwtAuth=new JwtAuth();
echo $jwtAuth->generate(1000);

parse.php

<?php

require_once "./jwt.php";

$token = $_GET["token"];

$jwtAuth = new JwtAuth();
echo $jwtAuth->parse($token);

实战二:token在前后端的分离的使用

需要做到两点: - 创建可复用的jwt类,必须包含生成和解析 - 创建前端并使用axios库进行交互

逻辑图如下所示:

login.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录页</title>
</head>

<body>
    用户名:<input id="userId" type="text" name="userId">
    密码:<input id="password" type="password" name="password" id="">
    <button onclick="login()">登录</button>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        //用axios方式调用服务端生成token
        function login() {
            //获取输入表单里的数据
            let userId = document.querySelector("#userId").value
            let password = document.querySelector("#password").value

            //装填json数据
            var params = new URLSearchParams()
            params.append('userId', userId)
            params.append('password', password)

            //axios验证
            axios.post('./passport_login.php', params).then(function (response) {
                if (response.data.status) {
                    setCookie("userId", userId, 7)
                    setCookie("token", response.data.token, 7)
                    window.location.href = "./person.html"
                } else {
                    alert("登录失败")
                }
            })
        }

        //以天为单位设置cookie
        function setCookie(cname, cvalue, exdays) {
            var d = new Date();
            d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
            var expires = "expires=" + d.toGMTString();
            document.cookie = cname + "=" + cvalue + "; " + expires;
        }
    </script>
</body>

</html>

person.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        verify()

        //验证cookie
        function verify() {
            //装填json数据
            var params = new URLSearchParams()
            params.append('userId', getCookie("userId")) //从cookie中获取用户名
            params.append('token', getCookie("token")) //从cookie中获取token

            //axios验证
            axios.post('./passport_verify.php', params).then(function (response) {
                if (response.data.status) {
                    document.writeln("<h2>欢迎你的访问,这是你的空间</h2>")
                } else {
                    alert("请登录后再访问")
                    window.location.href = "./login.html"
                }
            })
        }

        //获取cookie
        function getCookie(cname) {
            var name = cname + "=";
            var ca = document.cookie.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i].trim();
                if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
            }
            return "";
        }
    </script>
</body>

</html>

passport_login.php

<?php

require_once "./jwt.php";

$userId = $_POST["userId"];
$password =  $_POST["password"];

//当token和userId存在时执行
if (isset($userId) || isset($password)) {
    $realuserId = "dream335"; //假设获取realuserId的这个值来自数据库
    $realPassword = "123456"; //假设获取realPassword的这个值来自数据库

    //登录的userId是否和数据库的userId一致
    if ($userId == $realuserId && $password == $realPassword) {
        $jwtAuth = new JwtAuth();
        $token = $jwtAuth->generate($userId); //生成
        echo json_encode(array("status" => true, "token" => $token));
    } else {
        echo json_encode(array("status" => false, "token" => "非法登录是吧?"));
    }
}

passport_verify.php

<?php

require_once "./jwt.php";

$userId =  $_POST["userId"];
$token =  $_POST["token"];

//当token和userId存在时执行
if (isset($token) && isset($userId)) {
    $jwtAuth = new JwtAuth();
    $result = $jwtAuth->parse($token);

    //判断解析token得到的userId是否和客户端cookie保存的userId一致
    if ($result == $userId) {
        echo json_encode(array("status" => true, "cost" => 1299));
    } else {
        echo json_encode(array("status" => false, "text"=>"token error."));
    }
}

jwt.php

<?php
require __DIR__ . '/vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class JwtAuth
{
    private $key = 'w3ee7sauja91701h'; //这里填写你自己设置的密钥

    //加密
    //返回token
    public function generate($userId)
    {
        $payload = [
            'iss' => 'http://buaoye8.com', //jwt签发者 这个地方你可以自定义,这里我写的我们站点
            'aud' => 'http://buaoye8.com', //接收jwt的一方 这个地方你可以自定义,这里我写的我们站点
            "exp" => time() + 3600 * 2, // jwt的过期时间,过期时间必须要大于签发时间  时间戳+3600s*2   [时间戳是自1970 年1 月1 日(00:00:00 GMT)以来的秒数。]
            'iat' => time(), // jwt的签发时间
            'nbf' => time(), // 定义在什么时间之前,某个时间点后才能访问
            'data' => [
                'userId' => $userId, //账号ID
                // '...'=>.....
            ]
        ];

        $token = JWT::encode($payload, $this->key, 'HS256');  //encode加码
        return $token;
    }

    public function parse($token)
    {
        $decoded = JWT::decode($token, new Key($this->key, 'HS256')); //decode解码

        //如果用户的token解密后的一些数据(比如账户ID)和前端登录保存在cookie里的账户ID是吻合的,那么就说明是本人
        return $decoded->data->userId;
    }
}

63 ⚙️服务端 ↦ PHP开发技巧 __ 676 字
 PHP开发技巧 #16