基于 JWT-Auth 实现 API 验证

如果想要了解其生成Token的算法原理,请自行查阅相关资料

需要提及的几点:

  • 使用session存在的问题:

    • session和cookie是为了解决http无状态的方案。session是用户保存在服务器中的状态信息,cookie中则保存jsessionId,请求服务器时,服务器读取jsessionId从而确定用户的身份信息,而session+cookie用在restful接口上破坏了其“无状态”的特性,session运行时都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。这也是restful最致力于通过“无状态”解决的问题。如果使用session,那么restful也就没有什么意义了

    • session降低了系统扩展性。用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力

    • cookie不安全,很容易导致跨站请求伪造攻击(CSRF)

  • token存在的问题:

    • 如,如何确定token的过期时间?如果token的有效期过短,很容易造成用户用着用着就掉线的情况,降低用户体验。但目前看来好像并没有太好的办法,只能尽量延长token的有效期,或者每隔一次前端自动向服务端请求一次token

  • 基于 JWT-Auth 的 token 验证体系

    (亲测,希望这篇文章让大家少入坑)

  1. 运行软件版本

    • laravel 5.5

  2. 安装 JWT-Auth 扩展包

    composer require tymon/jwt-auth "1.5.*"

  3. 安装完后在配置文件config/app.php 中添加注册服务提供者和别名:

    ...
    'providers' => [
      ...
       Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
    ]
    ...
    'aliases' => [
      ...
       'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    ]
  4. 发布资源配置

    php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
  5. 运行以下命令生成密钥key在生成的config/jwt.php

    // 如果运行后报错,提示ERROR:Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist,将vendor\tymon\jwt-auth\src\Commands\JWTGenerateCommand.php文件中的 fire() 方法修改为 handle()即可正常生成秘钥
    php artisan jwt:generate
  6. 编辑 app/Http/Kernel.php 添加 jwt.auth 和 jwt.refresh 到应用路由中间件数组:

    protected $routeMiddleware = [
      ...
       'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
    //   'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
    ];
  7. JWTAuth 自身中间件\Tymon\JWTAuth\Middleware\GetUserFromToken 中包含了对生成token的各类情况的验证,以及异常的抛出。下面是其底层验证类GetUserFromToken::class

    // file_path : vendor\tymon\jwt-auth\src\Middleware\GetUserFromToken.php
    <?php

    /*
    * This file is part of jwt-auth.
    *
    * (c) Sean Tymon <tymon148@gmail.com>
    *
    * For the full copyright and license information, please view the LICENSE
    * file that was distributed with this source code.
    */

    namespace Tymon\JWTAuth\Middleware;

    use Tymon\JWTAuth\Exceptions\JWTException; //验证异常类
    use Tymon\JWTAuth\Exceptions\TokenExpiredException;//token过期异常验证类

    class GetUserFromToken extends BaseMiddleware
    {
       /**
        * Handle an incoming request.
        *
        * @param \Illuminate\Http\Request $request
        * @param \Closure $next
        * @return mixed
        */
       public function handle($request, \Closure $next)
      {
           if (! $token = $this->auth->setRequest($request)->getToken()) {
               return $this->respond('tymon.jwt.absent', 'token_not_provided', 400);
          }

           try {
               $user = $this->auth->authenticate($token);
          } catch (TokenExpiredException $e) {
               return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]);
          } catch (JWTException $e) {
               return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]);
          }

           if (! $user) {
               return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
          }

           $this->events->fire('tymon.jwt.valid', $user);

           return $next($request);
      }
    }

    其中,调用的respond 的方法在vendor\tymon\jwt-auth\src\Middleware\BaseMiddleware.php文件中

     /**
        * Fire event and return the response.
        *
        * @param string   $event
        * @param string   $error
        * @param int $status
        * @param array   $payload
        * @return mixed
        */
       protected function respond($event, $error, $status, $payload = [])
      {
           $response = $this->events->fire($event, $payload, true);

           return $response ?: $this->response->json(['error' => $error], $status);
      }

    可看到,当出现异常需要返回错误信息时,会连带返回一个fire event 的警告事件对象,这里不做详述。

  8. 由底层代码中,可以了解到,我们如果想自定义自己所需要的验证方法,可以将这GetUserFromToken::class 内容复制到我们自己自定义的中间件中。比如:

    • 创建自定义的验证中间件App\Http\Middleware\JwtAuth.php

      php artisan make:middleware JwtAuth
    • 全部复制到自定义的中间件中后,校验下中间件中需要的类是否应用完全,命名空间是否正确等等,检查无误后根据需要自行定义需要的验证功能。

      // demo 
      namespace App\Http\Middleware;

      use Tymon\JWTAuth\Exceptions\JWTException;
      use Tymon\JWTAuth\Exceptions\TokenExpiredException;
      use Closure;
      use Tymon\JWTAuth\Middleware\BaseMiddleware;

      class JwtAuth extends BaseMiddleware
      {
         public function handle($request, \Closure $next)
        {
             if (! $token = $this->auth->setRequest($request)->getToken()) {
                 return $this->respond('tymon.jwt.absent', 'token_not_provided', 400);
            }

             try {
                 $user = $this->auth->authenticate($token);
            } catch (TokenExpiredException $e) {
                 return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]);
            } catch (JWTException $e) {
                 return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]);
            }

             if (! $user) {
                 return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
            }

             $this->events->fire('tymon.jwt.valid', $user);

             return $next($request);
        }
      }
    • 定义完成后将自定义的中间件放入app\Http\Kernel.php的中间件数组中。

       protected $routeMiddleware = [
      ...
             //'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
             'jwt.auth_self' => \App\Http\Middleware\JwtAuth::class
        ];
    • 添加好后,即可在routes/api.php 中对需要控制的api路由进行验证控制

      Route::group(['middleware'=>'jwt.auth_self'],function(){
         // 需要控制的api路由
         // ... code
      });
  9. 我们现在可以对请求来的路由进行token的验证,那么接下来我们就需要生成这个token,让后续访问中间件中的请求路由都携带这个token就能实现验证。这里要提一下在安装JWT-Auth过程中生成的配置文件config/jwt.php

    <?php
       return [
      ...
       /*
       |--------------------------------------------------------------------------
       | User Model namespace
       |--------------------------------------------------------------------------
       |
       | Specify the full namespace to your User model.
       | e.g. 'Acme\Entities\User'
       |
       */
    // 设置你的用户model,默认为laravel自带的 User model
       'user' => 'App\User',
    ]

    如果需求需要,可在配置文件中修改用户mode ,但配置的model 中需要引用Illuminate\Foundation\Auth\User as Authenticatable,并继承,写法和User model一致

  10. 具体的请求登录以及获取token信息,登出等功能实现,可参考此文章

    Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证,这里简单提及下常用到的有关其token的方法

    <?php
       namespace App\Http\Controller; use Tymon\JWTAuth\JWTAuth; class Auth{
           public function test (JWTAuth $JWTAuth){
               
               // 获取请求携带中的token
               $token = $JWTAuth -> getToken();
               // 获取token中的用户信息
               $user = $JWTAuth -> parseToken() -> authenticate();
               // 销毁此次生成的token
               $JWTAuth->setToken( $JWTAuth->getToken() )->invalidate();
               // 自定义生成token,如果需要
               $JWTAuth->setToken('foo.bar.baz');
          }
    }

基于 JWT-Auth 实现 API 验证的更多相关文章

  1. ASP.NET Core WebApi基于JWT实现接口授权验证

    一.ASP.Net Core WebApi JWT课程前言 我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再 ...

  2. 基于JWT的Token身份验证

    ​ 身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie ​ cookie是 ...

  3. 基于JWT的web api身份验证及跨域调用实践

    随着多终端的出现,越来越多的站点通过web api restful的形式对外提供服务,很多网站也采用了前后端分离模式进行开发,因而在身份验证的方式上可能与传统的基于cookie的Session Id的 ...

  4. 前端和后端采用接口访问时的调用验证机制(基于JWT的前后端验证)(思路探讨)

    说明:基于前后端,尤其是使用Ajax请求的接口,现在市面上网页上调用的Ajax基本都是没有验证的,如果单独提取之后可以无线的刷数据. 继上一篇http://www.cnblogs.com/EasonJ ...

  5. asp.net core 2.0 web api基于JWT自定义策略授权

    JWT(json web token)是一种基于json的身份验证机制,流程如下: 通过登录,来获取Token,再在之后每次请求的Header中追加Authorization为Token的凭据,服务端 ...

  6. ASP.NET Web API 2系列(四):基于JWT的token身份认证方案

    1.引言 通过前边的系列教程,我们可以掌握WebAPI的初步运用,但是此时的API接口任何人都可以访问,这显然不是我们想要的,这时就需要控制对它的访问,也就是WebAPI的权限验证.验证方式非常多,本 ...

  7. 基于jwt的token验证

    一.什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该token被设计为紧凑且安全的,特别适用于分布 ...

  8. 基于Volley,Gson封装支持JWT无状态安全验证和数据防篡改的GsonRequest网络请求类

    这段时间做新的Android项目的client和和REST API通讯框架架构设计.使用了非常多新技术,终于的方案也相当简洁优雅.client仅仅须要传Java对象,server端返回json字符串, ...

  9. 在ASP.NET Web API 2中使用Owin基于Token令牌的身份验证

    基于令牌的身份验证 基于令牌的身份验证主要区别于以前常用的常用的基于cookie的身份验证,基于cookie的身份验证在B/S架构中使用比较多,但是在Web Api中因其特殊性,基于cookie的身份 ...

随机推荐

  1. Spring中applicationContext.xml详解

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  2. 【转载】MSDN-MDX#001 - 多维表达式 (MDX) 参考

    摘录于MSDN MDX 的一些重要概念 1. MDX 介绍 多维表达式 (MDX) 是用于在 Microsoft SQL Server Analysis Services (SSAS) 中处理和检索多 ...

  3. 解压命令tar zxvf中zxvf的意思

    x : 从 tar 包中把文件提取出来 z : 表示 tar 包是被 gzip 压缩过的,所以解压时需要用 gunzip 解压 v : 显示详细信息 f xxx.tar.gz : 指定被处理的文件是 ...

  4. 2018焦作网络赛 - Poor God Water 一道水题的教训

    本题算是签到题,但由于赛中花费了过多的时间去滴吧格,造成了不必要的浪费以及智商掉线,所以有必要记录一下坑点 题意:方格从1到n,每一格mjl可以选择吃鱼/巧克力/鸡腿,求走到n格时满足 1.每三格不可 ...

  5. 浏览器页面的显隐对js的setInterval()执行所产生的bug

    前段时间,所写的一个”js无间隙滚动效果“,当页面离开后,重新返回时,会出现动画的错乱.我以为是因为我代码逻辑的原因导致的,但是,当在火狐浏览器上进行浏览时却没有动画错乱的问题. 于是乎,在网上查找是 ...

  6. wusir FTP与HTTP文件传输之TCP Packet解析

    向服务器传输文件(上传或下载)时,FTP与HTTP是两种最常用的应用层协议,这两个协议都是基于TCP协议之上.如果深入到数据包内(Packet)进行查看时,FTP与HTTP进行文件传输时有什么特征代码 ...

  7. (转)如何在CentOS / RHEL 7上安装Elasticsearch,Logstash和Kibana(ELK)

    原文:https://www.howtoing.com/install-elasticsearch-logstash-and-kibana-elk-stack-on-centos-rhel-7 如果你 ...

  8. call()和apply()方法(切换上下文)

    call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. apply方法: 语法:apply ...

  9. orcale 之 PL/SQL的游标

    根据我们之前了解到的情况,SQL是面向集合的,我们的查询结果一般包含多条数据,而在PL/SQL 中的变量一般只能存放一条数据,因此变量是无法满足我们的需求的.这时候我们就需要引入游标来为我们解决问题了 ...

  10. master线程的主循环,后台循环,刷新循环,暂停循环

    InnoDB存储引擎的主要工作都是在一个单独的后台线程master thread中完成的.master thread的线程优先级别最高.其内部由几个循环(loop)组成:主循环(loop).后台循环( ...