zoukankan      html  css  js  c++  java
  • Lumen5.6使用JWT【最新教程】,亲身失败百次的总结

     

    一、前言

    1. 如果需要使用 Passport,可以参考在下之前的教程: 'Lumen5.4配置OAuth2.0【强迫症,就是要用最新版本的Lumen】' 。
    2. 由于原作者 文档 的简洁性,同时 Lumen 下的 JWT 与 Laravel 略有不同,导致新手初学不易理解。
    3. 在下经过多番考究,总结出 Lumen 使用 JWT 的基本过程。同时给出 JWT的介绍 
    4. 经过少数同学的反馈,教程太过仓促,现重新补充完整。

    二、说明

    1. 不知不觉 Lumen 已经更新到 '5.6.x' 版本,因此本文也紧跟脚步,使用最新版的 Lumen 进行讲解,最重要的是 Laravel/Lumen 5.6.x 版本只支持 'PHP7.1' 及以上。
    2. 本文使用 'tymon/jwt-auth: ^1.0.0-rc.2' 版本 (不推荐使用该扩展包的 0.5 版本) 的扩展包,搭配 Laravel 开箱即用的 'Auth' 组件实现  JWT 认证。
    3. 操作环境:'Windows 7' + 'PHP7.2' + 'MariaDB10.3'。上述环境在下均已测试多次,现分享出本人至今 'Windows' 下正常开发使用的 整合压缩包 

    三、准备部分

    1. 检查 'Windows' 上的开发环境是否正常。
      1.1. 查看 'PHP7.2' 环境:
       
      PHP

      1.2. 查看 'MariaDB10.3' 环境:
       
      MariaDB
    2. 安装 'PostMan' 以及 'Navicat Premium' ,其他类似软件产品亦可,根据个人喜好就行。
    3. 操作之前查看 'JWT的介绍' ,对理解后文大有裨益。

    四、实现部分

    1. 使用 'Composer' 安装最新的 Lumen 到本地。
    composer create-project laravel/lumen jwt-test --prefer-dist
    
    1. 进入项目 'jwt-test' 中,安装 'tymon/jwt-auth: ^1.0.0-rc.2' 到本地。
    composer require tymon/jwt-auth ^1.0.0-rc.2
    
    1. 刚刚初始化的 Lumen 项目可能会有一个小小的 BUG,因为 Lumen 默认会加载 Memcached 作为缓存,而部分开发者并没有使用 Memcached,所以需要在使用 Lumen项目之前,修改缓存配置。

    3.1.首先模拟 Laravel 目录结构,复制'vender/laravel/lumen-framework'下的 'config 目录到 'jwt-test' 根路径。复制完成以后 'jwt-test' 的根目录结构如下:

    /app
    ......others.......
    /config                                    <<<<<< 配置文件目录
    /vendor
    ......others.......
    

    3.2. 以后的配置文件,都只需要在根路径下的 'config目录操作即可,所以接着修改目录中的 cache.php 文件:

    # Dir: /jwt-test/config/cache.php
    <?php
    
    return [
         #### 修改为文件缓存
        'default' => env('CACHE_DRIVER', 'file'),  
        #### 同时删除了下面的Memcached配置
        'stores' => [
    
            'apc' => [
                'driver' => 'apc',
            ],
    
            'array' => [
                'driver' => 'array',
            ],
    
            'database' => [
                'driver' => 'database',
                'table'  => env('CACHE_DATABASE_TABLE', 'cache'),
                'connection' => env('CACHE_DATABASE_CONNECTION', 'mysql_a'),
            ],
    
            'file' => [
                'driver' => 'file',
                'path'   => storage_path('framework/cache'),
            ],
    
            'redis' => [
                'driver' => 'redis',
                'connection' => env('CACHE_REDIS_CONNECTION', 'cache'),
            ]
        ],
        'prefix' => env('CACHE_PREFIX', 'wz'),
    
    ];
    

    同时修改根路径下的 '.env 文件:

    # Dir: /jwt-test/.env
    ......others.......
    APP_KEY=9TBF8FrZZgYBoM0AzKjkii/yb6TJVm11        #### Lumen默认没有设置APP_KEY
    CACHE_DRIVER=file                               #### 修改为文件缓存
    ......others (包括MySQL的配置项) .......
    JWT_SECRET=Bi43uQQTHxLSnUaIOgTEUT1SkGHiOc1o     #### JWT编码时需要的Key
    
    1. 完成上述更改之后,快速启动项目,在 'PostMan' 中访问即可看见输出 Lumen 的版本信息。
       
      On Server

    本文使用以下指令快速启动服务。

    # Dir: /jwt-test/
    php -S localhost:8080 public/index.php
    
    1. 下面开始实现 JWT 功能。在下习惯在 'app' 路径想新建一个 'Models' 目录存放模型,因此之后的项目目录结构是:
    ......others.......
    /app
    ..........others.......
    ..../Models                                <<<<<< 模型文件目录
    /config                                    <<<<<< 配置文件目录
    /vendor
    ......others.......
    

    5.1 修改 'bootstrap' 文件夹下的 'app.php' 如下所示:

    <?php
    
    require_once __DIR__.'/../vendor/autoload.php';
    
    try {
        (new DotenvDotenv(__DIR__.'/../'))->load();
    } catch (DotenvExceptionInvalidPathException $e) {
        //
    }
    
    $app = new LaravelLumenApplication(
        realpath(__DIR__.'/../')
    );
    
    // 取消注释
    $app->withFacades();
    $app->withEloquent();
    
    $app->singleton(
        IlluminateContractsDebugExceptionHandler::class,
        AppExceptionsHandler::class
    );
    
    $app->singleton(
        IlluminateContractsConsoleKernel::class,
        AppConsoleKernel::class
    );
    
    // 取消注释
    $app->routeMiddleware([
        'auth' => AppHttpMiddlewareAuthenticate::class,
    ]);
    
    // 取消注释
    $app->register(AppProvidersAppServiceProvider::class);
    $app->register(AppProvidersAuthServiceProvider::class);
    $app->register(AppProvidersEventServiceProvider::class);
    // 新增JWT的注册
    $app->register(TymonJWTAuthProvidersLumenServiceProvider::class);
    
    $app->router->group([
        'namespace' => 'AppHttpControllers',
    ], function ($router) {
        require __DIR__.'/../routes/web.php';
    });
    
    return $app;
    
    

    5.2. 修改 'config' 文件夹下的 'auth.php' 如下所示:

    <?php
    return [
        'defaults' => [
            'guard' => 'api',
            'passwords' => 'users',
        ],
        'guards' => [
            'api' => [
                'driver' => 'jwt',                           #### 更改为JWT驱动
                'provider' => 'users',
            ],
        ],
        'providers' => [
            'users' => [
                'driver' => 'eloquent',
                'model'  => AppModelsUser::class,        #### 指定用于token验证的模型类
            ],
        ],
        'passwords' => [                                #### Lumen默认无session,所以该字段无意义
            //
        ],
    ];
    

    5.3. 修改 'app/Providers' 文件夹下的 'AuthServiceProvider.php' 如下所示:

    <?php
    
    namespace AppProviders;
    
    use AppModelsUser;
    use IlluminateSupportFacadesGate;
    use IlluminateSupportServiceProvider;
    
    class AuthServiceProvider extends ServiceProvider
    {
        /**
         * Register any application services.
         *
         * @return void
         */
        public function register()
        {
            //
        }
    
        /**
         * Boot the authentication services for the application.
         *
         * @return void
         */
        public function boot()
        {
            // 当使用auth中间件的api门卫的时候验证请求体
            $this->app['auth']->viaRequest('api', function ($request)
            {
                return app('auth')->setRequest($request)->user();
            });
        }
    }
    

    5.4. 修改 'app/Models' 文件夹下的 'User.php' 如下所示:

    <?php
    
    namespace AppModels;
    
    use IlluminateAuthAuthenticatable;
    use IlluminateDatabaseEloquentModel;
    use IlluminateContractsAuthAuthenticatable as AuthenticatableContract;
    use IlluminateContractsAuthAccessAuthorizable as AuthorizableContract;
    use LaravelLumenAuthAuthorizable;
    use TymonJWTAuthContractsJWTSubject;
    
    class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
    {
        use Authenticatable, Authorizable;
    
        protected $table = 'users';
    
        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = [
            'username', 'email',
        ];
    
        /**
         * The attributes excluded from the model's JSON form.
         *
         * @var array
         */
        protected $hidden = [
            'password',
        ];
    
        /**
         * JWT
         *
         * @author AdamTyn
         */
        public function getJWTIdentifier()
        {
            return $this->getKey();
        }
    
        /**
         * JWT
         *
         * @author AdamTyn
         */
        public function getJWTCustomClaims()
        {
            return [];
        }
    }
    

    5.5. 在 'app/Http/Controller' 文件夹下新建 'UserController.php',内容如下所示:

    <?php
    
    namespace AppHttpControllers;
    
    use IlluminateHttpRequest;
    use IlluminateSupportFacadesAuth;
    use IlluminateSupportFacadesDB;
    
    class AuthController extends Controller
    {
        /**
         * 登录
         *
         * @author AdamTyn
         *
         * @param IlluminateHttpRequest;
         * @return IlluminateHttpResponse;
         */
        public function login(Request $request)
        {
            $response = array('code' => '0');
    
            try {
                $user = AppModelsUser::where('username', $request->input('username'))
                    ->where('password', $request->input('password'))->first();
    
                if (!$token = Auth::login($user)) {
                    $response['code']     = '5000';
                    $response['errorMsg'] = '系统错误,无法生成令牌';
                } else {
                    $response['data']['user_id']      = strval($user->id);
                    $response['data']['access_token'] = $token;
                    $response['data']['expires_in']   = strval(time() + 86400);
                }
            } catch (QueryException $queryException) {
                $response['code'] = '5002';
                $response['msg']  = '无法响应请求,服务端异常';
            }
    
            return response()->json($response);
        }
    
        /**
         * 用户登出
         *
         * @author AdamTyn
         *
         * @return IlluminateHttpResponse;
         */
        public function logout()
        {
            $response = array('code' => '0');
    
            Auth::invalidate(true);
    
            return response()->json($response);
        }
    
        /**
         * 更新用户Token
         *
         * @author AdamTyn
         *
         * @param IlluminateHttpRequest;
         * @return IlluminateHttpResponse;
         */
        public function refreshToken()
        {
            $response = array('code' => '0');
    
            if (!$token = Auth::refresh(true, true)) {
                $response['code']     = '5000';
                $response['errorMsg'] = '系统错误,无法生成令牌';
            } else {
                $response['data']['access_token'] = $token;
                $response['data']['expires_in']   = strval(time() + 86400);
            }
    
            return response()->json($response);
        }
    }
    

    5.6. 最后,我们要利用 'auth' 中间件的 'api' 门卫,修改 'app/Http/Middleware' 文件夹下的 'Authenticate.php',内容如下所示:

    <?php
    
    namespace AppHttpMiddleware;
    
    use Closure;
    use IlluminateContractsAuthFactory as Auth;
    
    class Authenticate
    {
        /**
         * The authentication guard factory instance.
         *
         * @var IlluminateContractsAuthFactory
         */
        protected $auth;
    
        /**
         * Create a new middleware instance.
         *
         * @param  IlluminateContractsAuthFactory  $auth
         * @return void
         */
        public function __construct(Auth $auth)
        {
            $this->auth = $auth;
        }
    
        /**
         * 在进入控制器之前,判断并处理请求体
         *
         * @param  IlluminateHttpRequest  $request
         * @param  Closure  $next
         * @param  string|null  $guard
         * @return mixed
         */
        public function handle($request, Closure $next, $guard = null)
        {
           if ($this->auth->guard($guard)->guest()) {
               $response['code'] = '4001';
               $response['errorMsg'] = '无效令牌,需要重新获取';
               return response()->json($response);
           }
    
            return $next($request);
        }
    }
    

    5.7. 创建 'user' 数据表,在数据库中简单填充一条数据。需要注意的是 Lumen 默认数据库使用 'utf8mb4' 编码,如果数据库版本较低,需要修改'app/Providers/AppServiceProvider.PHP' 如下:

    <?php
    
    namespace AppProviders;
    
    use IlluminateSupportFacadesSchema;
    use IlluminateSupportServiceProvider;
    
    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Register any application services.
         *
         * @return void
         */
        public function register()
        {
            Schema::defaultStringLength(191);
        }
    }
    
     
    tb_users
    1. 运行测试。在'routers/router.php' 中添加相应的路由规则。
    <?php
    $router->post('login','AuthController@login');
    $router->group(['prefix'=>'/','middleware'=>'auth:api'],function () use ($router){
      $router->post('logout','AuthController@logout');
      $router->post('refresh','AuthController@refreshToken');
    });
    

    最后,可以得出以下测试结果。

     
    login
     
    logout
     
    refresh

    原文地址 https://www.jianshu.com/p/206d0a27a8d1

  • 相关阅读:
    sae-xhprof调试性能
    VC++常用函数
    C++资料收集&整理
    C++宽窄字符串转换
    #MySQL for Python(MySQLdb) Note
    VC++ ADO相关
    MFC各种控件的常见操作(逐步添加中......)
    关于Sql注入的那些事
    Python中socket经ssl加密后server开多线程
    网络编程
  • 原文地址:https://www.cnblogs.com/brady-wang/p/11627541.html
Copyright © 2011-2022 走看看