jwt token 鉴权验证

本文介绍了如何在ThinkPHP6.0框架中使用JWT进行身份验证。首先,定义了一个自定义异常处理函数`fault()`,接着配置了JWT的参数。然后,通过`firebase/php-jwt`扩展包封装了JWT功能类,包括创建、解析和校验token的方法。最后,创建了一个鉴权控制器,所有需要验证的API控制器可以继承这个基类,自动进行token的有效性检查和单点登录校验。
摘要由CSDN通过智能技术生成

1. JWT介绍


本文是在TP6.0使用JWT的示例

JWT全称: JSON Web Token,以 token 的方式代替传统的cookie、session模式,用于各服务器、客户端传递信息及签名验证

2. 新增自定义函数 fault()


在 app/common.php 中新增以下函数

/**
 * 抛出异常错误
 *
 * @param string  $msg
 * @param integer $code
 */
function fault(string $msg = "", $code = 201)
{
    throw new \Exception($msg, $code);
}

3. 新增配置文件 jwt.php


在全局配置目录 config 目录下新建 jwt.php 文件,文件内容如下

<?php
// +----------------------------------------------------------------------
// | JWT (Json Web Token) 配置
// +----------------------------------------------------------------------
// | Author: liang 30041321@qq.com
// +----------------------------------------------------------------------
return [
    'iss'             => 'liang',   // 签发者
    'aud'            => 'chen',    // 接收者
    'key'            => 'yang',    // 访问密钥
    'prefix'         => 'jwt_',    // 缓存前缀
    'exp'            => 864000,    // 过期时间,864000秒=10天
    'single_sign_on' => false,      // 单点登录 true 开启 false 关闭
];

4. JWT 功能封装类


安装扩展包

composer require firebase/php-jwt
<?php
// +----------------------------------------------------------------------
// | JWT (Json Web Token) 功能封装类
// +----------------------------------------------------------------------
// | Author: liang 30041321@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);
use Firebase\JWT\JWT;
class JwtAuth
{
    // +------------------------------------------------------------------
    // | 初始化配置
    // +------------------------------------------------------------------
    /**
     * 初始化配置
     */
    public function __construct()
    {
        $this->iss    = config('jwt.iss');     //签发者 可选
        $this->aud    = config('jwt.aud');     //接收该JWT的一方,可选
        $this->exp    = config('jwt.exp');     //过期时间,864000秒 = 10天
        $this->key    = config('jwt.key');     //访问秘钥
        $this->prefix = config('jwt.prefix');  //缓存前缀
    }
    // +------------------------------------------------------------------
    // | 创建、解析 token
    // +------------------------------------------------------------------
    /**
     * 创建token
     *
     * @param  array  $data
     * @return string token
     */
    public function encode(array $data)
    {
        $time = time(); //当前时间
        $token = [
            'iss'  => $this->iss,           //签发者 可选
            'aud'  => $this->aud,           //接收该JWT的一方,可选
            'iat'  => $time,                //签发时间
            'nbf'  => $time,                //(Not Before):某个时间点后才能访问,比如设置time+30,表示当前时间30秒后才能使用
            'exp'  => $time + $this->exp,   //过期时间
            'data' => $data,                //附加数据
        ];
        $token = JWT::encode($token, $this->key); // 创建token
        $this->cache($data['uid'], $token); // 将token存入缓存
        return $token; // 返回token
    }
    /**
     * 解析token
     *
     * @param string $token 前端请求携带的token
     */
    public function decode(string $token)
    {
        try {
            JWT::$leeway = 0; //当前时间减去60,把时间留点余地
            return JWT::decode($token, $this->key, ['HS256']); //HS256方式,这里要和签发的时候对应
        } catch (\Firebase\JWT\SignatureInvalidException $e) {  //签名不正确
            fault('签名不正确');
        } catch (\Firebase\JWT\BeforeValidException $e) {  // 签名在某个时间点之后才能用
            fault('登录未生效');
        } catch (\Firebase\JWT\ExpiredException $e) {  // token过期
            fault('登录过期');
        } catch (\Exception $e) {  //其他错误
            fault($e->getMessage());
        }
    }
    // +------------------------------------------------------------------
    // | 检测token
    // +------------------------------------------------------------------
    /**
     * 将用户token存入缓存,用于单点登录校验
     *
     * @param int    $id    用户id
     * @param string $token 服务器端生成的token
     */
    private function cache(int $uid, string $token)
    {
        // 缓存token
        cache($this->prefix . $uid, $token);
    }
    /**
     * 检测token是否已过期(单点登录)
     *
     * @param  int     $id    用户id
     * @param  string  $token 前端请求携带的token
     * @return boolean true   token 有效 false 已过期
     */
    public function checkToken(int $id, string $token)
    {
        // 判断是否开启单点登录校验 true 开启 false 关闭
        if (config('jwt.single_sign_on')) {
            // 获取缓存中该用户的token
            $cacheToken = cache($this->prefix . $id);
            // true 有效 false 已过期
            return $token === $cacheToken;
        } else {
            return true; // 没有开启单点登录直接返回true
        }
    }
}

5. JWT 鉴权控制器


创建鉴权控制器,所有需要进行Token校验的控制器只需要继承该控制器即可

php think make:controller api@Auth --plain

鉴权控制器文件内容如下:

<?php
// +----------------------------------------------------------------------
// | JWT (Json Web Token) 
// +----------------------------------------------------------------------
// | Author: liang 30041321@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace app\api\controller;
use JwtAuth;
use app\BaseController;
/**
 * JWT 鉴权控制器
 */
class Auth extends BaseController
{
    /**
     * 校验token是否有效
     */
    protected function initialize()
    {
        // 接收请求头中的Token
        $token = request()->header('token');
        // 初步校验token
        empty($token) && fault('token不能为空');
        // 解析token,返回生成token时的附加数据
        $this->jwt = app(JwtAuth::class)->decode($token)->data;
        // 获取附加数据中的用户id并转为整型
        $this->uid = (int) $this->jwt->uid;
        // 携带的token和缓存中的token进行比对(单点登录校验)
        if (!app(JwtAuth::class)->checkToken($this->uid, $token)) {
            fault('登录状态已过期', 401);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值