基于 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 实现基于API的用户认证的更多相关文章

  1. Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证

    在JavaScript前端技术大行其道的今天,我们通常只需在后台构建API提供给前端调用,并且后端仅仅设计为给前端移动App调用.用户认证是Web应用的重要组成部分,基于API的用户认证有两个最佳解决 ...

  2. 项目一:第十一天 2、运单waybill快速录入 3、权限demo演示-了解 5、权限模块数据模型 6、基于shiro实现用户认证-登录(重点)

    1. easyui DataGrid行编辑功能 2. 运单waybill快速录入 3. 权限demo演示-了解 4. Apache shiro安全框架概述 5. 权限模块数据模型 6. 基于shiro ...

  3. Linux下基于LDAP统一用户认证的研究

    Linux下基于LDAP统一用户认证的研究                   本文出自 "李晨光原创技术博客" 博客,谢绝转载!

  4. 5分钟搞懂:基于token的用户认证

    https://www.qikegu.com/easy-understanding/880 用户认证 用户认证或者说用户登录是确认某人确实是某人的过程,生活中靠身份证,网络上就要靠账号和密码.用户提供 ...

  5. 基于Ajax与用户认证系统的登录验证

    一.登录页面 from django.contrib import admin from django.urls import path from blog import views urlpatte ...

  6. springSecurity + jwt + redis 前后端分离用户认证和授权

    记录一下使用springSecurity搭建用户认证和授权的代码... 技术栈使用springSecurity + redis + JWT + mybatisPlus 部分代码来自:https://b ...

  7. 基于MongodbDB的用户认证-运维笔记

    MongoDB默认是不认证的,默认没有账号,只要能连接上服务就可以对数据库进行各种操作,MongoDB认为安全最好的方法就是在一个可信的环境中运行它,保证之后可信的机器才能访问它,可能这些对一些要求高 ...

  8. tp5使用jwt生成token,做api的用户认证

    首先 composer 安装  firebase/php-jwt github:https://github.com/firebase/php-jwt composer require firebas ...

  9. SpringSecurity学习之基于数据库的用户认证

    SpringSecurity给我们提供了一套最基本的认证方式,可是这种方式远远不能满足大多数系统的需求.不过好在SpringSecurity给我们预留了许多可扩展的接口给我们,我们可以基于这些接口实现 ...

随机推荐

  1. alert(1) to win 3

    function escape(s) { s = JSON.stringify(s); return '<script>console.log(' + s + ');</script ...

  2. PCB项目 X1 STC12C5A60S2-LQPF48

    单片机控制系统双层板STC51 简介: STC12C5A60S2主芯片,12MHz主频 12V电源输入,12/5/3V电源输出 4路0~12V可调10位ADC输入 4路1A大电流达林顿输出 4路INT ...

  3. 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 D Merchandise (斜率优化)

    Description: The elderly aunts always like to look for bargains and preferential merchandise. Now th ...

  4. TabController定义顶部tab切换

    前面通过DefaultTabController组件实现了AppBar里面的顶部导航切换,但是在项目中有数据请求,上拉加载更多等操作的时候,前面的写法,就不是很方便操作,因此,在flutter里面,还 ...

  5. postman 简单使用教程

    Postman 安装   Postman 接口测试(Collection)   Postman 接口测试(测试用例)Postman 接口测试(变量与参数化)Postman 接口测试(非 UI 运行模式 ...

  6. XML大作业

    XML大作业 共两题,均于实验上机完成 第一题:在xml文档中使用DTD 第二题:掌握使用xsl显示xml文件的基本方法 第一题: 一.实验目的 (1)通过本实验,使学生能够了解并掌握XML DTD的 ...

  7. Search Engine Hacking – Manual and Automation

    Search Engine Hacking – Manual and Automation Ethical Hacking Boot Camp OUR MOST POPULAR COURSE! CLI ...

  8. 【CDN+】Kafka 的初步认识与入门

    前言 项目中用到了Kafka 这种分布式消息队列来处理日志,本文将对Kafka的基本概念和原理做一些简要阐释 Kafka 的基本概念 官网解释: Kafka是最初由Linkedin公司开发,是一个分布 ...

  9. 测开之路八十二:匿名函数:lambda表达式

    # 匿名函数:lambda表达式# lambda 参数: 逻辑f = lambda name: print(name)f('tom') f2 = lambda x, y: x + yprint(f2( ...

  10. Support Vector Machine(3):Soft Margin 平衡之美

    很多材料上面讲道“引入Soft Margin的原因是因为数据线性不可分”,个人认为有些错误,其实再难以被分解的数据,如果我们用很复杂的弯弯绕曲线去做,还是可以被分解,并且映射到高维空间后认为其线性可分 ...