Laravel5.6+ JWT 多表多用户登录
使用Laravel5.6+JWT+dingo时。
之前用到laravel-5.4 的多表多用户配置,其中有一个严重的潜在bug。。当我拿到用户user表的token时,如果在后台admin表里面存在相同ID数据时,token是可以直接验证通过的。-例如我的用户表ID为100的用户.数据。如果后台管理表也存在这个ID为100数据。就可以直接用前台的用户token 去验证后台所有接口。细思极恐啊
然后我的解决思路时给各个用户表加一个字段,让他们各自有各自的身份。但是这样解决毕竟不符合框架的优雅性白白的增加代码逻辑,经过不懈寻找,百度。发现把laravel升到5.6可以解决这个问题。下面是实操记录:
1. 先使用 composer 安装 jwt-auth 执行下面命令
composer require "tymon/jwt-auth 1.*@rc"
2. 发布生成配置文件
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
3. 使用以下命令生成密钥
php artisan jwt:secret
4. 配置多 guard 来区分认证 在 config/auth.php
['guards' => [
'web' => [
'driver' => 'jwt',
'provider' => 'users',
],
//前端api验证
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
// 后台验证
'admin' => [
'driver' => 'jwt',
'provider' => 'admins',
],
//销售人员验证
'salesman' => [
'driver' => 'jwt',
'provider' => 'salesman',
]
],'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => User::class
],
'admins' => [
'driver' => 'eloquent',
'model' => Admin::class,
],
'salesman' => [
'driver' => 'eloquent',
'model' => ActivitySalesman::class,
]
]
5.更改相应的models文件如下。跟原来区别—主要 getJWTCustomClaims方法添加模型键值
<?php namespace App\Models; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * 获取会储存到 jwt 声明中的标识 * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); } /** * 返回包含要添加到 jwt 声明中的自定义键值对数组 * @return array */ public function getJWTCustomClaims() { return ['role' => 'user']; } } <?php namespace App\Models; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Tymon\JWTAuth\Contracts\JWTSubject; class Admin extends Authenticatable implements JWTSubject { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * 获取会储存到 jwt 声明中的标识 * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); } /** * 返回包含要添加到 jwt 声明中的自定义键值对数组 * @return array */ public function getJWTCustomClaims() { return ['role' => 'admin']; } }
6. 在 router/api.php
文件中创建路由信息 主要是使用中间件做验证 ->middleware([‘jwt.role:****’, ‘jwt.auth’]);
//普通用户登录 Route::group(['prefix' => 'auth'], function () { Route::post('login', 'AuthController@me')->middleware(['jwt.role:user', 'jwt.auth']); }); //后台用户登录 Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function () { Route::post('login', 'LoginController@me')->middleware(['jwt.role:admin', 'jwt.auth'])->name('me'); });
7. 创建中间件检测当前 token
对应的是哪个表 php artisan make:middleware JWTRoleAuth
<?php namespace App\Http\Middleware; use Closure; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; class JWTRoleAuth extends BaseMiddleware { /** * JWT 检测当前登录的平台 * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param null $role * @return mixed */ public function handle($request, Closure $next, $role = null) { try { // 解析token角色 $tokenRole = $this->auth->parseToken()->getClaim('role'); } catch (JWTException $e) { /** * token解析失败,说明请求中没有可用的token。 * 为了可以全局使用(不需要token的请求也可通过),这里让请求继续。 * 因为这个中间件的责职只是校验token里的角色。 */ return $next($request); } // 判断token角色。 if ($tokenRole != $role) { throw new UnauthorizedHttpException('jwt-auth', 'User role error'); } return $next($request); } }
大概原理应该就是在生成token的时候,给那条数据增加一个role字段。在验证token 的时候去检查role字段是否存在。跟我想法不谋而合
欢迎来收藏–https://www.talksphp.com/2020/09/05/larave-jwt-dinggo/