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/