JWT 实现基于API的用户认证

基于 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 <[email protected]>
     *
     * 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‘);
            }
        }
    

      

     

原文地址:https://www.cnblogs.com/rianley/p/11971233.html

时间: 2024-08-01 00:43:02

JWT 实现基于API的用户认证的相关文章

linux下ftp和ftps以及ftp基于mysql虚拟用户认证服务器的搭建

1.FTP协议:有命令和数据连接两种 命令连接,控制连接:21/tcp 数据连接: 主动模式,运行在20/tcp端口 和 被动模式,运行在随机端口 数据传输模式(自动模式):有二进制(mp3,jpg等)和文本(html)两种传输模式 ftp服务器端程序:wu-ftpd:vsftpd pureftpd Filezilla Serv-U ftp客户端程序:CLI文本模式命令:ftp lftp GUI图形界面软件:gftpd FlashFXP Cuteftp Filezilla vsftpd:命名为V

Vsftpd基于MySQL实现用户认证

ftp简介: ftp:File Transfer Protocol,文件传输协议:FTP是应用层协议,使用C/S架构,工作于20/tcp,21/tcp. FTP使用交互式访问模式,两个并行TCP连接,一个控制连接,一个数据连接,控制连接用于在客户机和服务器之间发送控制信息,比如用户和密码,改变远程目录和命令,上传下载文件等,数据连接用于真正发送数据.ftp有两种工作模式,主动模式(Active),被动模式(Passive). 数据: 命令连接:文件管理类命令,始终在线的连接 数据连接:数据传输,

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

用户认证 用户认证或者说用户登录是确认某人确实是某人的过程,生活中靠身份证,网络上就要靠账号和密码.用户提供账号和密码,网站通过与数据库中保存的账号与密码比对确认用户身份. 基于token的用户认证 基于token的用户认证原理很简单.让用户输入账号和密码,然后获得一个token(令牌),该token允许用户在不使用账号和密码的情况下访问特定的资源.一旦获得token,用户就获得了在一段时间内对特定资源的访问权限. 这个过程类似酒店开房,在酒店前台认证身份.登记入住,这个步骤相当于网站的登录,然

vsftpd基于pam虚拟用户认证,还怕泄漏账号么?

一.ftp简要介绍 ftp是一个很古老的协议了,是一种基于明文传输的C/S架构协议.ftp基于tpc21.20端口,其中21端口为命令端口,20端口为数据端口.ftp命令连接同其他TCP连接一样,不过数据连接有两种模式: 主动模式,也称作PORT模式:命令请求端口时,服务器端为减少等待,主动将数据发送给客户端:使用本机的20端口请求客户端的端口.这里有个问题:服务器端想要主动连接客户端就需要知道客户端的端口号,可是客户端根本没有启动任何端口给服务器端.协议设计中服务器端根据客户端的命令连接端口(

实现FTP基于MYSQL虚拟用户认证

两台主机实现:一台作为ftp服务器,一台作为mysql服务器 host1 : 192.168.1.107 vsftpd pam_mysql.so host2 : 192.168.1.109 mariadb mariadb-server 一.准备数据库 1.安装数据库并启动mysql ~]# yum install mariadb mariadb-server -y ~]# systemctl start mariadb 2.创建vsftpd服务的虚拟数据库及用户列表 1)创建vsftp的数据库

基于apache整合svn服务器,基于mysql对用户认证

运行环境: 系统环境# uname -srLinux 2.6.32-504.16.2.el6.centos.plus.x86_64# cat /etc/issueCentOS release 6.6 (Final) Apache: httpd-2.4.12 svn: subversion-1.8.13 MySQL相关:  mariadb-10.0.17-linux-x86_64 mod_auth_mysql-3.0.0 其他依赖环境 pcre-8.37 serf-1.3.8 scons-2.3.

用户认证:基于jwt和session的区别和优缺点

背景知识: Authentication和Authorization的区别: Authentication:用户认证,指的是验证用户的身份,例如你希望以小A的身份登录,那么应用程序需要通过用户名和密码确认你真的是小A. Authorization:授权,指的是确认你的身份之后提供给你权限,例如用户小A可以修改数据,而用户小B只能阅读数据. 由于http协议是无状态的,每一次请求都无状态.当一个用户通过用户名和密码登录了之后,他的下一个请求不会携带任何状态,应用程序无法知道他的身份,那就必须重新认

前后端分离之JWT用户认证

在前后端分离开发时为什么需要用户认证呢?原因是由于HTTP协定是不储存状态的(stateless),这意味着当我们透过帐号密码验证一个使用者时,当下一个request请求时它就把刚刚的资料忘了.于是我们的程序就不知道谁是谁,就要再验证一次.所以为了保证系统安全,我们就需要验证用户否处于登录状态. 传统方式 前后端分离通过Restful API进行数据交互时,如何验证用户的登录信息及权限.在原来的项目中,使用的是最传统也是最简单的方式,前端登录,后端根据用户信息生成一个token,并保存这个 to

翻译:WebApi 认证--用户认证Oauth解析

The Web API v2用户认证模板提供了流行的应用用户认证场景,如.使用本地帐号的用户名密码认账 (包括创建用户.设置和修改密码)以及使用第三方的认证方式,如facebook,google等等– 在本地中包含了外部帐号的连接 所有的这些均通过使用一个OAuth2认证服务进行. To make all that happen the template combines quite a bit of new stuff together: OWIN, Katana authentication