Laravel 的 Restful Api 基于JWT-AUTH 验证配置

1,081 阅读3分钟

在此文章中,我们将学习如何使用 JWT 身份验证在 Laravel 中构建 restful API 。 JWT 代表 JSON Web Tokens 。 我们还将使用 API 为用户产品创建功能齐全的 CRUD 应用。 在使用跨平台应用程序时, API 是一个非常不错的选择。 除了网站,您的产品可能还有 Android 和 iOS 应用程序。 在这种情况下, API 也是同样出色的,因为您可以在不更改任何后端代码的情况下编写不同的前端。 使用 API 时,只需使用一些参数点击 GET , POST 或其他类型的请求,服务器就会返回 JSON (JavaScript Object Notation) 格式的一些数据,这些数据由客户端应用程序处理。

创建新项目

#使用composer安装
composer create-project --prefer-dist laravel/laravel jwt
#使用Latavel安装器
Laravel new jwt

如果出现找不到包可切换镜像源

  • 全局配置阿里镜像源

    composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
    
  • 取消配置:

    composer config -g --unset repos.packagist
    

配置JWT-AUTH扩展

如果您正在使用 Laravel 5.5 或以上版本,请运行以下命令来获取 dev-develop 版本的 JWT 包(亲测)

composer require tymon/jwt-auth

如果您正在使用 Laravel 5.4 或以下版本,那么要运行下面这条命令(未亲测)

composer require tymon/jwt-auth:dev-develop --prefer-source

对于 Laravel 版本 低于 5.5 的应用,您还要在 config/app.php 文件中设置服务提供者和别名。

'providers' => [
    ....
    Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
    ....
],
'aliases' => [
    ....
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
    ....
],

如果您的 Laravel 版本为 5.5 或以上,Laravel 会进行「包自动发现」。

发布配置文件

对于 5.5 或以上版本 的 Laravel,请使用下面这条命令来发布配置文件(使用Laravel8亲测)

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

对于之前 之前版本的 Laravel,那么应该运行下面这条命令(未亲测)

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

生成JWT密钥

对于 5.5 或以上版本 的 Laravel,请使用下面这条命令来发布配置文件(使用Laravel8亲测)

php artisan jwt:secret

对于之前 之前版本的 Laravel,那么应该运行下面这条命令(未亲测)

php artisan jwt:generate

注册中间件

protected $routeMiddleware = [
    ....
    'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];

这个中间件会通过检查请求中附带的令牌来校验用户的认证。如果用户未认证,这个中间件会抛出 UnauthorizedHttpException 异常。

设置API路由

找到routes/api.php 添加对应路由

Route::post('login', 'ApiController@login');
Route::post('register', 'ApiController@register');

Route::group(['middleware' => 'auth.jwt'], function () {
    Route::get('logout', 'ApiController@logout');

    Route::get('user', 'ApiController@getAuthUser');

    Route::get('products', 'ProductController@index');
    Route::get('products/{id}', 'ProductController@show');
    Route::post('products', 'ProductController@store');
    Route::put('products/{id}', 'ProductController@update');
    Route::delete('products/{id}', 'ProductController@destroy');
});

路由服务

一、一开始的项目并默认带有命名空间前缀,需要自己加上(我创建的新项目并无添加直接设置api路由会出现控制器不存在的错误)路径app/Providers/RouteServiceProvider.php

方法1:直接添加命名空间属性

protected $namespace = 'App\Http\Controllers';

方法2:添加命名空间属性后增加三个路由映射方法--可注释掉原本boot中的方法

    protected $namespace = 'App\Http\Controllers';     /**
     * The controller namespace for the application.
     *
     * When present, controller route declarations will automatically be prefixed with this namespace.
     *
     * @var string|null
     */
    // protected $namespace = 'App\\Http\\Controllers';

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        $this->configureRateLimiting();
        // parent::boot();
        // $this->routes(function () {
        //     Route::prefix('api')
        //         ->middleware('api')
        //         ->namespace($this->namespace)
        //         ->group(base_path('routes/api.php'));

        //     Route::middleware('web')
        //         ->namespace($this->namespace)
        //         ->group(base_path('routes/web.php'));
        // });
    }

     /**
     * Define the routes for the application.
     *
     * @return void
     */
    public function map()
    {
        $this->mapApiRoutes();
        $this->mapWebRoutes();
    }

    /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

    /**
     * Define the "api" routes for the application.
     *
     * These routes are typically stateless.
     *
     * @return void
     */
    protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('api')
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }

二、设置config/auth.php文件,设置api使用jwt验证

'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
 ],
'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

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

JWT 身份验证逻辑

让我们使用 JWT 身份验证在 laravel 中写 Restful API 的逻辑。 用户注册时需要姓名,邮箱和密码。

创建一个API控制器

php artisan make:controller ApiController

修改控制器

<?php

namespace App\Http\Controllers;

use App\Http\Requests\RegisterAuthRequest;
use App\User;
use Illuminate\Http\Request;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

class ApiController extends Controller
{
    public $loginAfterSignUp = true;

    public function register(Request $request)    {
        $user = new User();
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();
        if ($this->loginAfterSignUp) {
            return $this->login($request);
        }
        return response()->json([
            'success' => true,
            'data' => $user
        ], 200);
    }

    public function login(Request $request)
    {
        $input = $request->only('email', 'password');
        $jwt_token = null;

        if (!$jwt_token = JWTAuth::attempt($input)) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid Email or Password',
            ], 401);
        }

        return response()->json([
            'success' => true,
            'token' => $jwt_token,
        ]);
    }

    public function logout(Request $request)
    {
        $this->validate($request, [
            'token' => 'required'
        ]);

        try {
            JWTAuth::invalidate($request->token);

            return response()->json([
                'success' => true,
                'message' => 'User logged out successfully'
            ]);
        } catch (JWTException $exception) {
            return response()->json([
                'success' => false,
                'message' => 'Sorry, the user cannot be logged out'
            ], 500);
        }
    }

    public function getAuthUser(Request $request)
    {
        $this->validate($request, [
            'token' => 'required'
        ]);
        $user = JWTAuth::authenticate($request->token);
        return response()->json(['user' => $user]);
    }
}

如果生成令牌的过程中出现该错误

Tymon\JWTAuth\Exceptions\JWTException: Could not create token: Using integers for registered date claims is deprecated, please use DateTimeImmutable objects instead

百度后解决方案是

'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class 改成 'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class

到此已经成功配置JWT-AUTH 验证,已经可以使用接口令牌了

参考文档:learnku.com/laravel/t/2…