• ThinkPHP 集成 jwt 技术 token 验证


    一、思路流程

    1. 客户端使用用户名和密码请求登录
    2. 服务端收到请求,验证用户名和密码
    3. 验证成功后,服务端会签发一个token,再把这个token返回给客户端
    4. 客户端收到token后可以把它存储起来,比如放到cookie中
    5. 客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带
    6. 服务端收到请求,然后去验证客户端请求里面带着的token,如果验证成功,就向客户端返回请求数据

    二、安装 firebase/php-jwt

    composer require firebase/php-jwt
    
    • 1

    三、封装token类

    因为我这个是多应用,然后我就只在index应用(只提供api接口)下设置了token类

    在这里插入图片描述

    <?php
    namespace app\index\server;
    
    use Firebase\JWT\JWT;
    use Firebase\JWT\Key;
    
    class Token
    {
    
        protected $key;
    
        public function __construct()
        {
            //从配置信息这种或取唯一字符串,你可以随便写比如md5('token')
            $this->key = 'adcdefg';
        }
    
    
        /**
         * 生成token
         * @param $uid
         * @return mixed
         */
        function generateToken($uid)
        {
    
            //获取当前时间戳
            $currentTime = time();
            $data = array(
                "iss" => $this->key,        //签发者 可以为空
                "aud" => '',             //面象的用户,可以为空
                "iat" => $currentTime,   //签发时间
                "nbf" => $currentTime,   //立马生效
                "exp" => $currentTime + 7200, //token 过期时间 两小时
                "data" => [              //记录的userid的信息,这里是自已添加上去的,如果有其它信息,可以再添加数组的键值对
                    'uid' => $uid,
                ]
            );
            //生成token
            $token = JWT::encode($data, $this->key, "HS256");  //根据参数生成了 token
            return $token;
        }
    
        /**
         * 校验token时效性
         */
        public function chekToken($token)
        {
    
            $status=array("code"=>2);
            try {
                JWT::$leeway = 60;//当前时间减去60,把时间留点余地
                $decoded = JWT::decode($token,new Key($this->key,'HS256')); //HS256方式,这里要和签发的时候对应
                $arr = (array)$decoded;
                $res['code']=1;
                $res['data']=$arr['data'];
                return $res;
    
            } catch(\Firebase\JWT\SignatureInvalidException $e) { //签名不正确
                $status['msg']="签名不正确";
                return $status;
            }catch(\Firebase\JWT\BeforeValidException $e) { // 签名在某个时间点之后才能用
                $status['msg']="token失效";
                return $status;
            }catch(\Firebase\JWT\ExpiredException $e) { // token过期
                $status['msg']="token失效";
                return $status;
            }catch(\Exception $e) { //其他错误
                $status['msg']="未知错误";
                return $status;
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    四、创建中间件,检验Token校验时效性

    创建中间件命令:

    php think make:middleware CheckToken
    
    • 1

    在这里插入图片描述

    
    declare (strict_types = 1);
    
    namespace app\middleware;
    
    class CheckToken
    {
      /**
         * 处理请求 token 验证
         *
         * @param \think\Request $request
         * @param \Closure       $next
         * @return Response
         */
      public function handle($request, \Closure $next)
      {
        //第一步先取token
        $token = $request->header('token');
        //jwt进行校验token
        $res = (new TokenServer())->chekToken($token);
        if ($res['code'] != 1 ){
          return json(['error_code'=>999,'msg'=>$res['msg'],'data'=>''],400);
        }
        $request->uid = $res['data']->uid;
        return $next($request);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    五、配置路由中间件

    在config/middleware.php中注册中间件

    在这里插入图片描述

    
    // 中间件配置
    return [
        // 别名或分组
        'alias'    => [
            // 注册中间件
            'check' => [
                app\middleware\CheckToken::class
            ],
        ],
        // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
        'priority' => [],
    ];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在app/api/route/route.php路由文件中进行使用,进行使用中间件校验token

    在这里插入图片描述

    
    use think\facade\Route;
    // restfull 资源路由
    Route::resource('a', 'TestR');
    
    // 路由分组
    Route::group('a',function (){
    
    })->middleware('check');
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    六、写几个测试方法,通过postman去验证

    
    declare (strict_types = 1);
    
    namespace app\index\controller;
    
    use app\index\server\Token as TokenServer;
    use think\Request;
    
    
    use think\annotation\route\Resource;
    
    // 资源控制器
    /**
     * @Resource("a")
     */
    class TestR
    {
        /**
         * 显示资源列表
         *
         * @return \think\Response
         */
        public function index(Request $request)
        {
            // 假定用户名为robin和密码为123456即为正确的账号
            if($request->param('uname') == 'robin'&& $request->param('upwd')=='123456')
            {
                $uid = $request->param('uname');
                // 设置token
                $token = (new TokenServer())->generateToken($uid);
                $data = ['name' => 'thinkphp', 'status' => '1','token'=>$token];
                // 给前端返回json字符串,同时前端将token获取并且存入到以后的所有操作中
                return show(config("status.success"),"请求成功",$data);
            }else{
                return show(config("status.error"),"用户名密码错误",null);
            }
    
        }
    
        /**
         * 保存新建的资源
         *
         * @param  \think\Request  $request
         * @return \think\Response
         */
        public function save(Request $request)
        {
            // 用update 来验证一下token
            $token = $request->param('token');
            $rs = checkToken($token);
            return json($rs);
        }
    
      // ....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    1. 模拟登录测试

    在这里插入图片描述

    1. 模拟前端携带token参数访问
      在这里插入图片描述
  • 相关阅读:
    codeforces:E. Madoka and The Best University【因数list + 分析拆解 + 公因数特性 + 欧拉函数】
    03 _ 复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?
    0825学习笔记(文件)
    Swagger的简单介绍,集成,以及如何在生产环境中关闭swagger,在测试和开发环境中自动打开
    劳保鞋批发,你找对地方了吗?
    NLP之Bert实现文本多分类
    金仓数据库KingbaseES客户端编程接口指南-JDBC(9. JDBC 读写分离)
    EPICS简单实例1 -- 向IOCSH注册自己的函数
    05-React组件的组合使用
    MAC 地址简化概念(有线 MAC 地址、无线 MAC 地址、MAC 地址的随机化)
  • 原文地址:https://blog.csdn.net/m0_63622279/article/details/132575734