Lumen5.6使用JWT【最新教程】,亲身失败百次的总结
一、前言
- 如果需要使用 Passport,可以参考在下之前的教程: 'Lumen5.4配置OAuth2.0【强迫症,就是要用最新版本的Lumen】' 。
- 由于原作者文档的简洁性,同时 Lumen 下的 JWT 与 Laravel 略有不同,导致新手初学不易理解。
- 在下经过多番考究,总结出 Lumen 使用 JWT 的基本过程。同时给出JWT的介绍。
- 经过少数同学的反馈,教程太过仓促,现重新补充完整。
二、说明
- 不知不觉 Lumen 已经更新到 '5.6.x' 版本,因此本文也紧跟脚步,使用最新版的 Lumen 进行讲解,最重要的是 Laravel/Lumen 5.6.x 版本只支持 'PHP7.1' 及以上。
- 本文使用 'tymon/jwt-auth: ^1.0.0-rc.2' 版本 (不推荐使用该扩展包的 0.5 版本) 的扩展包,搭配 Laravel 开箱即用的 'Auth' 组件实现 JWT 认证。
- 操作环境:'Windows 7' + 'PHP7.2' + 'MariaDB10.3'。上述环境在下均已测试多次,现分享出本人至今 'Windows' 下正常开发使用的整合压缩包。
三、准备部分
- 检查 'Windows' 上的开发环境是否正常。
1.1. 查看 'PHP7.2' 环境:PHP1.2. 查看 'MariaDB10.3' 环境:
MariaDB - 安装 'PostMan'以及'Navicat Premium',其他类似软件产品亦可,根据个人喜好就行。
- 操作之前查看 'JWT的介绍',对理解后文大有裨益。
四、实现部分
- 使用 'Composer' 安装最新的 Lumen 到本地。
composer create-project laravel/lumen jwt-test --prefer-dist
- 进入项目 'jwt-test' 中,安装 'tymon/jwt-auth: ^1.0.0-rc.2' 到本地。
composer require tymon/jwt-auth ^1.0.0-rc.2
- 刚刚初始化的 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
- 完成上述更改之后,快速启动项目,在 'PostMan' 中访问即可看见输出 Lumen 的版本信息。
On Server
本文使用以下指令快速启动服务。
# Dir: /jwt-test/
php -S localhost:8080 public/index.php
- 下面开始实现 JWT 功能。在下习惯在 'app' 路径想新建一个 'Models' 目录存放模型,因此之后的项目目录结构是:
......others.......
/app
..........others.......
..../Models <<<<<< 模型文件目录
/config <<<<<< 配置文件目录
/vendor
......others.......
5.1 修改 'bootstrap' 文件夹下的 'app.php' 如下所示:
<?php
require_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' 如下所示:
<?php
return [
'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' 如下所示:
<?php
namespace 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' 如下所示:
<?php
namespace 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',内容如下所示:
<?php
namespace 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',内容如下所示:
<?php
namespace 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' 如下:
<?php
namespace 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);
}
}
- 运行测试。在'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');
});
最后,可以得出以下测试结果。
原文地址 https://www.jianshu.com/p/206d0a27a8d1
Lumen5.6使用JWT【最新教程】,亲身失败百次的总结的更多相关文章
- JWT 基础教程
原文地址:JWT 基础教程 博客地址:http://www.extlight.com 一.前言 针对前后端分离的项目,大多是通过 token 进行身份认证来进行交互,今天将介绍一种简单的创建 toke ...
- VS2019打包WPF安装程序最新教程
VS2019打包WPF安装程序最新教程,使用Visual Studio 2019开发的WPF程序如果想要打包为安装程序,除了在VS2019找到WPF项目类库直接右键发布之外,更常用的还是将其打包为ex ...
- 使用VS 2019发布.net core程序并部署到IIS的最新教程
不管你是使用.net core开发的是web api还是网站类的程序,如果你是部署到IIS,那么下面的内容都适合于你,不会将.net core程序部署到IIS的朋友,可以看看这篇手把手教你部署.net ...
- React Gatsby 最新教程
React Gatsby 最新教程 https://www.gatsbyjs.com/docs/quick-start/ https://www.gatsbyjs.com/docs/tutorial/ ...
- VuePress 最新教程
VuePress 最新教程 https://vuepress.vuejs.org/ https://github.com/vuejs/vuepress VuePress plugins 插件通常会为 ...
- Storybook 最新教程
Storybook 最新教程 Storybook is the most popular UI component development tool for React, Vue, and Angul ...
- 如何找回微信小程序源码?2020年微信小程序反编译最新教程 小宇子李
前言:在网上看了找回微信小程序源码很多教程,都没法正常使用.微信版本升级后,会遇到各种报错, 以及无法获取到wxss的问题.查阅各种资料,最终解决,于是贴上完整的微信小程序反编译方案与教程. 本文章仅 ...
- 极路由器刷机安装ss插件最新教程
极路由器系统升级后,旧的插件已不可用,这里是最新极路由器刷机教程,可实现绑定ss代理账号的功能. 获取root权限 安装开发者插件,获取root权限,请先登录极路由器后台(电脑浏览器访问 192.16 ...
- SSM框架搭建最新教程(超详细)
个人认为使用框架并不是很难,关键要理解其思想,这对于我们提高编程水平很有帮助.不过,如果用都不会,谈思想就变成纸上谈兵了!!!先技术,再思想.实践出真知. 1.基本概念 1.1.Spring Spr ...
随机推荐
- Spring cloud微服务安全实战-3-4 API安全机制之认证(1)
本节开始讲认证相关的东西.注意事项,出现问题的对应的解决方案. 先写用户注册的服务,注册一些用户信息进去.注册也是我们安全体系的一部分 注册 UserController里面的create方法 先修改 ...
- 【FreeMarker】FreeMarker使用(三)
搭建一个 1.FreeMarker取值 <!DOCTYPE html> <html> <head> <meta charset="UTF-8&quo ...
- Python - Django - request 对象
request.method: 获取请求的方法,例如 GET.POST 等 views.py: from django.shortcuts import render, HttpResponse # ...
- Intellij IDEA集成mybatis-generator插件自动生成数据库实体操作类
Intellij IDEA集成mybatis-generator插件自动生成数据库实体操作类 转载至:https://blog.csdn.net/fishinhouse/article/details ...
- STM32驱动模数转换芯片ADS1120(基础知识篇)第1篇
1. 先看下ADS1120的结构图,ADS1120是个比较奇葩的ADC模数转换器,因为比较适用于热电阻之类的温度采集器.看下图,有个MUX多路复用器,应该是选择两个差分信号去测试,通过输入多路复用器 ...
- AI - TensorFlow - 示例05:保存和恢复模型
保存和恢复模型(Save and restore models) 官网示例:https://www.tensorflow.org/tutorials/keras/save_and_restore_mo ...
- console.log()和alert()的区别
一直都是知道console.log()和alert()是有区别的,但是具体有什么区别就不清楚了,后来在权威指南里注意到了说alert()具有侵入性才来查一查两者的具体区别. 查询到的区别: alert ...
- C++编译提示 default argument are given of parameter ..
如果定义一个类的构造函数时,带有默认的入参值,在cpp文件中实现构造函数时,是不能带的!否则就会提示该种类型的编译错误. //.h文件: namespace Ui { class Task; } cl ...
- PHP 与操作判断奇偶
/** * 判断奇偶数 * @param $n * @return int */ function isOdd($n){ // $a & $b And(按位与) 将把 $a 和 $b 中都为 ...
- 转:对JavaScript中闭包的理解
关于 const let var 总结: 建议使用 let ,而不使用var,如果要声明常量,则用const. ES6(ES2015)出现之前,JavaScript中声明变量只有 ...