1.安装jwt

composer require firebase/php-jwt

2.创建服务类Jwt生成、验证token
(1)在extra文件夹下新建system.php配置文件

<?php
return [
    // Jwt 参数配置
    'token_name' => 'Authorization', // 令牌名称
    'jwt_iss' => 'https://xxx.xxxxx.net', // 签发者
    "jwt_aud" => 'https://xxx.xxxxx.net', // 接收该JWT的一方
    'jwt_key' => 'xxxxxx',  // 加密密钥
    'jwt_algo' => 'HS256', // 算法
    'jwt_exp_hour' => 24, // jwt过期时间
    
    'pass_salt'  => 'xxxxxxx',
];

(2)创建服务类JwtHandle.php

<?php

namespace app\lib\server;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use think\Controller;
use think\Request;

class JwtHandle extends Controller
{
    protected $key;
    protected $jwtAlgo;
    protected $jwtIss;
    protected $jwtAud;
    protected $tokenName;

    public function __construct()
    {
        parent::__construct();
        $this->key = config('system.jwt_key');
        $this->jwtAlgo = config('system.jwt_algo');
        $this->jwtIss = config('system.jwt_iss');
        $this->jwtAud = config('system.jwt_aud');
        $this->tokenName = config('system.token_name');
    }

    // 获取token的方法(校验用户输入的用户名密码正确后调用,生成token)
    public function getToken($info, $idName = 'userId')
    {
        $jwtExpHour = config('system.jwt_exp_hour');
        $time = time();
        $payload = [
            'iss' => $this->jwtIss,
            'aud' => $this->jwtAud,
            'iat' => $time,
            'nbf' => $time,
            'exp' => $time + 3600 * $jwtExpHour,
            'username'=>$info['user_name'],
            (string)$idName => $info['user_id']
        ];
        $token = JWT::encode($payload, $this->key, $this->jwtAlgo);
        return $token;
    }

    // 校验token的方法(在需要校验token的接口中调用)
    public function checkToken($flag = false, $_token = null)
    {
        // 去掉token中的'Bearer '
        $token = !empty($_token) ? $_token : substr(Request::instance()->header($this->tokenName), 7);
        if (empty($token))
            return ['status' => false, 'msg' => 'token为空'];
        try {
            $token = think_decrypt($token);
            $decoded = JWT::decode($token, new Key($this->key, $this->jwtAlgo));

            // 校验token是否为空
            if (empty($decoded)) {
                return ['status' => false, 'msg' => 'token为空'];
            }
            // 校验token是否合法
            if ($decoded->iss !== $this->jwtIss || $decoded->aud !== $this->jwtAud) {
                return ['status' => false, 'msg' => 'token不合法'];
            }
            // 校验token是否过期
            if ($decoded->exp < time()) {
                return ['status' => false, 'msg' => 'token已过期'];
            }
            // 校验token是否正确
            if ($decoded->userId === "") {
                return ['status' => false, 'msg' => 'token参数为空'];
            }
            if ($flag) {
                return $decoded;
            }
            return ['status' => true, 'msg' => 'token正确'];
        } catch (\Exception $e) {
            return ['status' => false, 'msg' => '未知错误' . $e->getMessage()];
        }
    }

    // 获取用户id
    public function getUserId()
    {
        $decoded = $this->checkToken(true);
        return $decoded->userId;
    }
    public function getUserName()
    {
        $decoded = $this->checkToken(true);
        return $decoded->username;
    }
}

2.登录验证
(1)在模型SysUserModel.php中添加login方法

public function login($param)
    {
        $where['user_name'] = ['=', $param['username']];
        $info = DataHandle::getOne($this, $where);
        if (empty($info))
            return ['code' => 500, 'msg' => '帐号不存在!'];

        if ($info['del_flag'] == 2)
            return ['code' => 500, 'msg' => '帐号已删除!'];

        if ($info['status'] > 0)
            return ['code' => 500, 'msg' => '帐号已停用!'];

        if ($info['password'] != md5($param['password']))
            return ['code' => 500, 'msg' => '密码错误! '];

        unset($info['password']);
        // 添加scope数据权限查询'data_scope'参数
        $info['data_scope'] = (new SysRoleModel())->getDataScopeByUserId($info['user_id']);
        $token = (new JwtHandle())->getToken($info);
        return ['code' => 200, 'msg' => '操作成功', 'token' => think_encrypt($token)];
    }

(2)考虑jwt生成token安全性,再次对token进行加解密。在公共common.php加入方法think_encrypt、think_decrypt

/**
 * 系统加密方法
 * @param string $data 要加密的字符串
 * @param string $key 加密密钥
 * @param int $expire 过期时间 单位 秒
 * @return string
 */
if (!function_exists('think_encrypt')) {
    function think_encrypt($data, $key = '', $expire = 0)
    {
        $key = md5(empty($key) ? config('system.pass_salt') : $key);
        $data = base64_encode($data);
        $x = 0;
        $len = strlen($data);
        $l = strlen($key);
        $char = '';

        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) $x = 0;
            $char .= substr($key, $x, 1);
            $x++;
        }

        $str = sprintf('%010d', $expire ? $expire + time() : 0);

        for ($i = 0; $i < $len; $i++) {
            $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1))) % 256);
        }

        $str = str_replace(array('+', '/', '='), array('-', '_', ''), base64_encode($str));
        return strtoupper(md5($str)) . $str;
    }
}

/**
 * 系统解密方法
 * @param  string $data 要解密的字符串 (必须是think_encrypt方法加密的字符串)
 * @param  string $key 加密密钥
 * @return string
 */
if (!function_exists('think_decrypt')) {
    function think_decrypt($data, $key = '')
    {
        $key = md5(empty($key) ? config('system.pass_salt') : $key);
        $data = substr($data, 32);
        $data = str_replace(array('-', '_'), array('+', '/'), $data);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        $data = base64_decode($data);
        $expire = substr($data, 0, 10);
        $data = substr($data, 10);

        if ($expire > 0 && $expire < time()) {
            return '';
        }
        $x = 0;
        $len = strlen($data);
        $l = strlen($key);
        $char = $str = '';

        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) $x = 0;
            $char .= substr($key, $x, 1);
            $x++;
        }

        for ($i = 0; $i < $len; $i++) {
            if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
                $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
            } else {
                $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
            }
        }
        return base64_decode($str);
    }
}

更多推荐