laravel5.8集成JWT记录

laravel一直是被大家说是非常优雅的框架,这次无所事事也就翻开文档看看,并且之后也使用laravel5.8适配了一个reactAdmin后台管理系统,前后端分离,所以决定使用JWT。

原本在thinkPHP中使用jwt还是非常顺利简单的,不过在laravel上却花费了一番力气才整理完毕。

1composer安装
$ composer require tymon/jwt-auth 1.0.0-rc.1
2配置
  1. 发布配置文件
# 这条命令会在 config 下增加一个 jwt.php 的配置文件
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
  1. 生成加密密钥
# 这条命令会在 .env 文件下生成一个加密密钥,如:JWT_SECRET=foobar
$ php artisan jwt:secret
  1. 创建权限管理模型

    laravel对于权限等等模块都有提供相应功能,这也是我在使用时候比较费解的问题,例如框架内部集成权限是使用User模型,其实根据业务不同肯定需要改动,正常情况我更喜欢自己去实现,毕竟文档中并没有详细的讲解其提供模块的实现,使用过程中花费时间去摸索也不容易啊。

namespace App\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class Admin extends BaseModel implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract,
    JWTSubject
{
    use Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;

    protected $hidden = ['password'];

    protected $fillable = ['name', 'password'];

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }

    public function roles() {
        return $this->belongsToMany(Role::class);
    }
}
  1. 注册两个 Facade
    这两个 Facade 并不是必须的,但是使用它们会给你的代码编写带来一点便利。
# ./config/app.php
'aliases' => [
    ...
    // 添加以下两行
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
],
  1. 修改 auth.php
#./config/auth.php
//此处为我项目的配置
'guards' => [
    'web' => [
        'driver' => 'jwt',
        'provider' => 'admins',
    ],

    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
        'hash' => false,
    ],
],

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

    'admins' => [
        'driver' => 'eloquent',
        'model' => \App\Models\Admin::class,
    ],
],
3注册登录实现
  1. 控制器、注册、登录
    这里说一下laravel权限封装,没有暴露出具体实现,我也没探究式如何生成密码的,所以账号一定要先注册后再进行登录。
namespace App\Http\Controllers\Admin;

use App\Exceptions\AuthException;
use App\Exceptions\LoginException;
use App\Http\Controllers\Controller;
use App\Logic\AuthLogic;
use App\Models\Admin;
use App\Utils\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Tymon\JWTAuth\Facades\JWTAuth;

class AuthController extends Controller
{

    /**
     * 后台管理员登录
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws AuthException
     * @throws LoginException
     */
    public function login(Request $request)
    {
        if (! $token = auth("web")->attempt([
            "name" => $request->input("userName"),
            "password" => $request->input("password")
        ])) {
            throw new LoginException(['msg' => '用户名或密码错误']);
        }
        if (JWTAuth::user()->status === 0) {
            throw new AuthException(['msg' => '用户暂无权限登录']);
        }
        //将token返回给前端
        JWTAuth::user()->token = $token;
        //存储用户相关权限
        (new AuthLogic(JWTAuth::user()))->saveAuthoritiesToCache();
        return Response::result(JWTAuth::user());
    }

    /**
     * 后台管理员注册
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request)
    {
        $name = $request->userName;
        $password = $request->password;
        $user = Admin::create(['name' => $name, 'password' => Hash::make($password)]);
        $user->token = JWTAuth::fromUser($user);
        return Response::result($user);
    }
}
  1. 定义路由
# ./routes/web.php
Route::middleware('validator:Auth')->namespace('Admin')->prefix('admin')->group(function () {
    // 后台登录
    Route::post('login', 'AuthController@login');

    //后台注册
    Route::post('register', 'AuthController@register');

});
4中间件校验token并获取用户信息、权限等
  1. 创建校验token中间件
namespace App\Http\Middleware;

use App\Exceptions\LoginException;
use App\Exceptions\TokenException;
use Closure;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Facades\JWTAuth;

class CheckToken
{
    /**
     * 校验登录JWT的token
     * @param Request $request
     * @param Closure $next
     * @return mixed
     * @throws LoginException
     * @throws TokenException
     */
    public function handle(Request $request, Closure $next)
    {
        try {
            if (!$user = JWTAuth::parseToken()->authenticate()) {
                throw new LoginException(['msg' => "未登录,请先登录"]);
            }
            //如果想向控制器里传入用户信息,将数据添加到$request里面
            $request->attributes->add(["user" => $user]);//添加参数
            return $next($request);
        } catch (TokenExpiredException $e) {
            throw new TokenException(['msg' => "token 过期"]);
        } catch (TokenInvalidException $e) {
            throw new TokenException(['msg' => "token 无效"]);
        } catch (JWTException $e) {
            throw new TokenException(['msg' => "缺少token"]);
        }
    }
}
  1. 创建校验token权限中间件
namespace App\Http\Middleware;

use App\Exceptions\AuthException;
use App\Logic\AuthLogic;
use Closure;
class CheckTokenAuth
{
	//不需要经过该中间件校验的路由
    protected $except = [
        "admin/menus/getUserRoutes",
    ];

    /**
     * 校验登录用户token绑定的路由权限
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     * @throws AuthException
     */
    public function handle($request, Closure $next)
    {

        if (
            !(new AuthLogic($request->user()))->checkAuth($request->route()->uri) &&
            !in_array($request->route()->uri, $this->except)
        ) {
            throw new AuthException();
        }
        return $next($request);
    }
}

  1. 注册并合并上面创建的两个中间件
    修改文件 ./app/Http/Kernel.php
protected $middlewareGroups = [
    ...

    //校验token,并且校验访问路由权限
    'api.auth' => [
        'jwt.api.token',
        'jwt.api.auth',
    ],
];
    
protected $routeMiddleware = [
    //登录校验
    'jwt.api.token' => \App\Http\Middleware\CheckToken::class,

    //登录用户访问api路由权限校验
    'jwt.api.auth' => \App\Http\Middleware\CheckTokenAuth::class,
];

  1. 路由配置
# ./routes/web.php
// Admin 模块
Route::middleware('api.auth')->namespace('Admin')->prefix('admin')->group(function () {

    Route::middleware('validator:Admin')->prefix('/admins')->group(function () {
        // 获取管理员列表
        Route::get('getAdmins', 'AdminController@getAdmins');
    })
});
  1. 控制器
namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Logic\AdminLogic;
use App\Logic\AuthLogic;
use App\Models\Admin;
use App\Utils\Response;
use Illuminate\Http\Request;

class AdminController extends Controller
{
    /**
     * 获取管理员列表
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getAdmins(Request $request) {
        $admins = Admin::with("roles")->paginate($request->pageSize);
        return Response::result($admins);
    }
}
5参考项目

ReactAdmin-Laravel

你可能感兴趣的:(php)