Laravel JWT 多表多用户登录

使用 JWT 方式来实现 API 多用户多表认证

1、先使用 composer 安装 jwt-auth 执行下面命令
     composer require "tymon/jwt-auth 1.*@rc"
2、laravel版本大于等于5.5版本可以省略此步骤 注册服务提供者 config/app.php
'providers' => [
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]

'aliases' => [
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
    'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
]

3、发布生成配置文件

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

4、使用以下命令生成密钥

php artisan jwt:secret

5、配置多guard来区分认证 打开 config/auth.php

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt',  // 默认是 token
            'provider' => 'users',
        ],
        // 新增admins 模块
        'admin' => [
            'driver' => 'jwt',
            'provider' => 'admins',
        ]
    ],


    'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ]
],

6、生成相应的数据表 执行下面命令 php artisan make:model Models/Admin -m 生成 model 与对应的表

Schema::create('admins', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

7、执行 php artisan migrate 生成表结构, 执行下面 sql 语句生成数据

# users 表
insert into `users` ( `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`) values ( 'test123', '994914376@qq.com', '$2y$10$52EQECqdeemEXGoAs9u4iO4gN3CmtC0OY/8snDUEweANw4BQZbiCe', 'z9prihuBKigCGtaEA0GMp6TcyLnFTICUW4F5fuIK6RnZl2o7RC4HQ7BkPOBm', '2019-06-25 03:39:48', '2019-06-25 03:39:48');

# admins 表
insert into `admins` ( `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`) values ( 'Harvey Jenkins', 'mdouglas@example.com', '$2y$10$DVjo80fNjiPP1qlsW1eRsem9iwXNsClhFgZPQAp47flRUxyk8l/HG', 'XQmmqzC91R', '2019-06-25 05:06:18', '2019-06-25 05:06:18');

8、更改相应的 Model文件

App\Models\User

<?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'];
    }
}

App\Models\Admin

<?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'];
    }
}

9、在 router/api.php文件中创建路由信息

# 普通用户登录
Route::group(['prefix' => 'auth'], function () {
    Route::post('login', 'AuthController@login');
    Route::post('logout', 'AuthController@logout');
    Route::post('refresh', 'AuthController@refresh');
    Route::post('me', 'AuthController@me')->name('me')->middleware(['jwt.role:user', 'jwt.auth']);
});

# 后台用户登录
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function () {
    Route::post('login', 'LoginController@login');
    Route::post('logout', 'LoginController@logout');
    Route::post('refresh', 'LoginController@refresh');
    Route::post('me', 'LoginController@me')->middleware(['jwt.role:admin', 'jwt.auth'])->name('me');
});

10、创建相应的控制器

AuthController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;

class AuthController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login']]);

    }

    /**
     * @return JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);

        if (! $token = auth('api')->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    public function me()
    {
        return response()->json(auth('api')->user());
    }

    public function logout()
    {
        auth('api')->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    public function refresh()
    {
        return $this->respondWithToken(auth('api')->refresh());
    }

    /**
     * @param $token
     * @return JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60
        ]);
    }
}

Admin/LoginController.php

<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;

class LoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:admin', ['except' => ['login']]);

    }

    /**
     * @return JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);

        if (! $token = auth('admin')->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    public function me()
    {
        return response()->json(auth('admin')->user());
    }

    public function logout()
    {
        auth('api')->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    public function refresh()
    {
        return $this->respondWithToken(auth('api')->refresh());
    }

    /**
     * @param $token
     * @return JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60
        ]);
    }
}

11、创建中间件检测当前 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);
    }
}

12、使用 postman测试接口

laravel JWT 多表多用户登录

laravel JWT 多表多用户登录

laravel JWT 多表多用户登录

laravel JWT 多表多用户登录

13、到此 jwt 多用户 多表认证就已经完成,如有问题和建议可以留言交流

注:以上的一些方式是直接参考网上的部份然后进行整理

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
994914376
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 31

@994914376 楼主,你这里是不是缺少一个步骤:
在 app/Http/Kernel.php 中注册中间件:

 protected $routeMiddleware = [
        // ...省略 ...

        // 多表jwt验证校验
        'jwt.role' => \App\Http\Middleware\JWTRoleAuth::class,
    ];

博客:Laravel jwt 多表(多用户端)验证隔离
两个帖子,结合着看,豁然开朗。解决了我的疑惑。

4年前 评论

这样做就是为了防止串号。

4年前 评论
seeker-x2y 2年前

我测试发现,不用写中件间和设置 getJWTCustomClaimsjwt-auth 这个可以自动区分。
jwt-auth 1.0.0-rc.4.1
laravel 5.8

4年前 评论
十七岁程序员想当歌手 (作者) 4年前
十七岁程序员想当歌手 (作者) 4年前

@十七岁程序员想当歌手
同意。
https://github.com/tymondesigns/jwt-auth/p...

    ['sub' => $subject->getJWTIdentifier()],
    ['prv' => get_class($subject)],

prv 可能在此基础上又加密了一下。

4年前 评论

登录正常返回access_token了,然后使用access_token获取用户信息:return response()->json(auth('admin')->user());却报错 "message": "User not found", "status_code": 401,

4年前 评论
TommyTu 3年前
丶simon 3年前
994914376

@raulzhou token是否在header忘记加Bearer + token了

4年前 评论

@十七岁程序员想当歌手 我的就是这个版本,中间件用jwt.auth就区分不了,还是走默认

4年前 评论

file

请问在Admin/LoginController.php中,这两个auth方法里面的参数不应该是admin吗

4年前 评论

@十七岁程序员想当歌手

Laravel: 5.5.*
tymon/jwt-auth: "1.0.0-rc.4.1"

遇到诡异的问题,必须要在 user 表里面存在 id 和 admin 表里 id 一样才可以用。。。 目前问题是换成 auth:「$guard」 验证,jwt.role 中间件来过滤

4年前 评论
鲤子 3年前
十七岁程序员想当歌手 4年前
胖猪猪 3年前
zero123 3年前
Zccc 3年前

auth('admin')->attempt返回值一直是true,求教如何处理

3年前 评论
994914376 (楼主) 3年前
osang (作者) 3年前
osang (作者) 3年前

如果默认的guard里面不存在这个id的话,jwt-auth验证会不通过,返回user not found,有就通过,并且会返回设置的guard里面的数据,请问楼主怎么解决这个的,因为jwt-auth这个中间件一直用默认的guard来判断id在表中是否存在的

3年前 评论
october 3年前

laravel7 是不是有bug啊,明明路由里面配置了guard jwt可以解析到但是还是去到users表查询

3年前 评论

我的jwt多用户认证的admin没有签发token。。

2年前 评论
tomcath 2年前

attempt 返回不是个bool么???

2年前 评论

为啥返回异常的时候只是返回 { "message": "Unauthenticated." } 而到不了自定义的异常返回里面,求解

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!