首页> 实战笔录 >PHP开发笔记 >ThinkPHP ThinkPHP

TP6使用JWT实现中间件验证Token,验证用户登录信息

作者:小萝卜 2024-05-08 浏览 1166

简介TP6使用JWT实现中间件验证Token,创建token解析token

开发环境和依赖

      在开始之前,我们需要确保开发环境已经正确设置。以下是本文所使用的环境和依赖。请根据您的需求进行相应地更改。

      PHP 7.2 或更高版本

      ThinkPHP 6.0.0 或更高版本

      Firebase JWT PHP 库

步骤1:安装 Firebase JWT PHP 库

 
composer require firebase/php-jwt


步骤2:创建Token类

      为了便于管理和使用 JWT,我们创建一个名为Token的类来处理 JWT 验证的各个方面。这个类将包括创建令牌,验证令牌,获取令牌信息等功能。

      在 app/common 目录下创建 Token.php 文件,并添加以下代码:

<?php
namespace app\common;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\BeforeValidException;
class Token
{
    private static $key = 'testadmin';  //生成token的秘钥
    private static $alg = 'HS256'; //生成token的方式

    /**
     * 生成token
     * @param $data
     * @param $expiration
     * @return string
     */
    public static function createToken($data, $expiration = 3600)
    {
        $payload = [
            'iss' => 'localhost', //签发者 可以为空
            'aub' => 'user_name', //面象的用户,可以为空
            'sub' => 'token', //主题
            'iat' => time(), //签发时间
            'nbf' => time(), //在什么时候jwt开始生效
            'exp' => time() + $expiration, //过期时间
            'data' => $data ///这里是自已添加上去的,如果有其它信息,可以再添加数组的键值对
        ];

        return JWT::encode($payload, self::$key, self::$alg);
    }

    /**
     * 解析token
     * @param $token
     * @return \stdClass
     */
    public static function decodeToken($token)
    {
        $status = array("code" => 500);
        try {
            JWT::$leeway = 60; //当前时间减去60,把时间留点余地
            $decoded = JWT::decode($token, new Key(self::$key, self::$alg)); //HS256方式,这里要和签发的时候对应
            $arr = (array)$decoded;
            $res['code'] = 200;
            $res['data'] = $arr;
            return $res;
        } catch (SignatureInvalidException $e) { //签名不正确
            $status['msg'] = "签名不正确";
            return $status;
        } catch (BeforeValidException $e) { // 签名在某个时间点之后才能用
            $status['msg'] = "token未生效";
            return $status;
        } catch (ExpiredException $e) { // token过期
            $status['msg'] = "token失效";
            return $status;
        } catch (Exception $e) { //其他错误
            $status['msg'] = "未知错误";
            return $status;
        }
    }

    /**
     * 解析token返回数据部分
     * @param $token
     * @return false
     */
    public static function getDataByToken($token)
    {
        $decoded = self::decodeToken($token);

        return $decoded;
    }

    /**
     * 验证token令牌是否有效
     * @param $token
     * @return bool
     */
    public static function verifyToken($token)
    {
        $result = false;
        try {
            //$decoded = self::decodeToken($token);
            $result = true;
        } catch (Exception $e) {
            // Invalid token
        }
        return $result;
    }
}


步骤3:登陆时生成token

 
use app\common\Token;


$token_data['id'] = $adata['id'];
$token_data['gid'] = $adata['gid'];

$token = Token::createToken($token_data);
 

步骤4:在中间件中验证解析令牌(在/应用目录/middleware/目录下新建adminlogin.php中间件文件)

 
<?php
declare (strict_types = 1);

namespace app\admin\middleware;
use app\common\Token;
class AdminLogin
{
    /**
     * 处理请求
     * 利用jwt验证token中间件
     * @param \think\Request $request
     * @param \Closure       $next
     * @return Response|\think\response\Json
     */
    public function handle($request, \Closure $next)
    {

        $white_list  = [
            '/captcha.html',
            '/index/login',
            '/index/getcaptcha'
        ]; // 白名单,不用验证登录

        $request_uri = $_SERVER['REQUEST_URI'];
        $pathinfo    = explode('?',$request_uri)[0];
        $pathinfo    = strtolower($pathinfo);

        //排除白名单
        if(!in_array($pathinfo, $white_list)) {
            //验证登录
            if (!$request->header('Authorization')) {
                return json(['code' => 20001, 'msg' => 'token不存在']);
            }

            $header = $request->header('Authorization');
            $token = substr($header, 7);  //这里是去掉Authorization 中的 Bearer
            if (Token::verifyToken($token)) {
                $data = Token::getDataByToken($token);
                if($data['code']==200){
                    $request ->admin_data = (array)$data['data']['data'];
                }else{
                    return json(['code' => 20002, 'msg' => $data['msg']]);
                }

                return $next($request);
            } else {
                return json(['code' => 20002, 'msg' => 'token有误']);
            }

        }
        return $next($request);
    }
}
 

步骤5:设置路由(我这里设置的是应用中间件)

      在/应用目录/middleware.php文件中新增应用中间件

<?php
// 全局中间件定义文件
return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
    // \think\middleware\LoadLangPack::class,
    // Session初始化
    \think\middleware\SessionInit::class,
    //登录验证
    'admin_login'=>\app\admin\middleware\AdminLogin::class, //取别名
];


步骤6:在控制器中使用解析的token令牌信息

 
   /**
     * 登陆后获取管理员信息
     * @return array
     * @param  token  string
     */
    public function getManager()
    {
        $admin_data = request()->admin_data;

        $manager = new ManagerModel();

        $data = $manager->field('id,admin_name,avatar,names,login_time,alogin_time')->find($admin_data['id'])->toArray();

        return $this->success('获取成功',$data);
    }

在控制器中,您可以通过调用reques()->admin_data来访问经过身份验证的 JWT 中存储的数据。

很赞哦! (1)

文章评论

    高端网站建设