JWT 的使用

1、composer 引入 jwt 组件
composer require firebase/php-jwt

 

2、编写代码(根据实际需要修改)
<?php
declare(strict_types = 1);

namespace app\controllers;

use app\common\Helper;
use Firebase\JWT\JWT;
use yii\base\Controller;

class TestController extends Controller
{
    /**
     * 登录
     *
     * @throws \Exception
     */
    public function actionLogin()
    {
        // 验证验证码、用户名及密码
        if (false) {
            return Helper::msg(0, '登录失败,验证码、用户名或密码错误');
        } else {
            // 如果验证通过,假设从数据库中获取到的用户信息
            $userInfo = [
                'user_id' => 10000,
                'user_name' => 'haveyb',
                'is_admin' => 1,
                'menus' => [1, 2, 6, 13],
            ];
            // 生成jwt,以供后续请求时,后端服务器身份校验
            $token = $this->getJwt($userInfo);
            // 返回给前端的数据,以供前端本次请求的数据显示
            $data = [
                'user_id' => $userInfo['user_id'],
                'user_name' => 'haveyb',
                'menus' => $userInfo['menus'],
                'token' => $token
            ];
            return Helper::msg(1, 'success', $data);
        }
    }

    /**
     * 验证用户是否登录,如果登录,返回用户id等信息,否则返回false
     */
    public function actionCheck()
    {
        // 假设客户端请求的token(正常流程应该是放在前端请求过来的header头中或者cookie中)
        $requestToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvd3d3LmhhdmV5Yi5jb20iLCJjcmVhdGVfdGltZSI6MTU4NjMzMzAwMSwidXNlcl9pZCI6MTAwMDAsImlzX2FkbWluIjoxfQ.VrGWf6nfhy8g5f-MufZK7J_OnOkUKiVHp4p9E9JavQw';
        // jwt 加解密密钥
        $secret = $this->getJwtSecret();
        // jwt 加解密方式
        $alg = $this->getJwtAlg();
        // 验证token是否有效
        try {
            $check = (array)JWT::decode($requestToken, $secret, [$alg]);
        } catch (\Exception $e) {
            return Helper::msg(0, '用户登录信息错误');
        }
        // 验证 jwt 有效期(可以有,可以没有,建议添加上)
        if (time() - $check['create_time'] > 86400) {
            return Helper::msg(0, '用户登录信息错误');
        }
        // 到数据库中查询用户id等信息,返回给调用的方法
        return Helper::msg(1, 'success', $check);
    }

    /**
     * 获取json web token
     *
     * @param $userInfo
     * @return string
     */
    private function getJwt($userInfo)
    {
        $secret = $this->getJwtSecret();
        $alg = $this->getJwtAlg();
        $currentTime = time();
        $returnData = [
            'iss' => 'https://www.haveyb.com',
            'create_time' => $currentTime,
            'user_id' => $userInfo['user_id'],
            'is_admin' => $userInfo['is_admin'],
        ];
        return JWT::encode($returnData, $secret, $alg);
    }

    /**
     * 返回jwt密钥
     *
     * @return string
     */
    private function getJwtSecret()
    {
        return 'BQXSD0PxCFPN/3xa06/94PWm++0ZKOHw83kP0=';
    }

    /**
     * 返回jwt加解密方式
     *
     * @return string
     */
    private function getJwtAlg()
    {
        return 'HS256';
    }

}

 

3、校验结果:

访问 login 方法

访问check方法

说明:check 方法实际使用中应该由具体的方法调用,为的是校验身份以及获取用户id等信息。

 

4、安全上的防范

由于 jwt 一旦被其他人获取了,就可以伪造用户的身份进行操作,因此再安全上一定要注意。

(1)使用 https 协议

在http超文本传输协议加入SSL层,它在网络间通信是加密的,所以需要加密证书

(2)保证服务端用于生成token的签名不泄露,并比较晦涩难懂

(3)加入token 过期时间的校验

这样,即使其他人拿到token,没过多少时间,就过期了

(4)加入 token ip的校验,一旦用户ip发生变化,则要求用户重新登录

和加入过期时间类似,只要在生成token时,加入user_ip字段,后面客户端请求时,再校验下 user_ip