手记

Lumen5.6使用JWT【最新教程】,亲身失败百次的总结

二、说明

  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<?phpreturn [     #### 修改为文件缓存
    '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_KEYCACHE_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' 如下所示:

<?phprequire_once __DIR__.'/../vendor/autoload.php';try {
    (new Dotenv\Dotenv(__DIR__.'/../'))->load();
} catch (Dotenv\Exception\InvalidPathException $e) {    //}

$app = new Laravel\Lumen\Application(
    realpath(__DIR__.'/../')
);// 取消注释$app->withFacades();
$app->withEloquent();

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);// 取消注释$app->routeMiddleware([    'auth' => App\Http\Middleware\Authenticate::class,
]);// 取消注释$app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
$app->register(App\Providers\EventServiceProvider::class);// 新增JWT的注册$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);

$app->router->group([    'namespace' => 'App\Http\Controllers',
], function ($router) {    require __DIR__.'/../routes/web.php';
});return $app;

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

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

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

<?phpnamespace App\Providers;use App\Models\User;use Illuminate\Support\Facades\Gate;use Illuminate\Support\ServiceProvider;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' 如下所示:

<?phpnamespace App\Models;use Illuminate\Auth\Authenticatable;use Illuminate\Database\Eloquent\Model;use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;use Laravel\Lumen\Auth\Authorizable;use Tymon\JWTAuth\Contracts\JWTSubject;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',内容如下所示:

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;use Illuminate\Support\Facades\Auth;use Illuminate\Support\Facades\DB;class AuthController extends Controller{    /**
     * 登录
     *
     * @author AdamTyn
     *
     * @param \Illuminate\Http\Request;
     * @return \Illuminate\Http\Response;
     */
    public function login(Request $request)
    {
        $response = array('code' => '0');        try {
            $user = \App\Models\User::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 \Illuminate\Http\Response;
     */
    public function logout()
    {
        $response = array('code' => '0');

        Auth::invalidate(true);        return response()->json($response);
    }    /**
     * 更新用户Token
     *
     * @author AdamTyn
     *
     * @param \Illuminate\Http\Request;
     * @return \Illuminate\Http\Response;
     */
    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',内容如下所示:

<?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Contracts\Auth\Factory as Auth;class Authenticate{    /**
     * The authentication guard factory instance.
     *
     * @var \Illuminate\Contracts\Auth\Factory
     */
    protected $auth;    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Auth\Factory  $auth
     * @return void
     */
    public function __construct(Auth $auth)
    {        $this->auth = $auth;
    }    /**
     * 在进入控制器之前,判断并处理请求体
     *
     * @param  \Illuminate\Http\Request  $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' 如下:

<?phpnamespace App\Providers;use Illuminate\Support\Facades\Schema;use Illuminate\Support\ServiceProvider;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


0人推荐
随时随地看视频
慕课网APP

热门评论

有个问题,我jwt携带的数据只能是user表中的数据,能不能自定义呢

查看全部评论