侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

使用Laravel集成JWT认证开发RestfulApi

Laravel  /  管理员 发布于 8年前   699

在此文章中,我们将学习如何使用 JWT 身份验证在 Laravel 中构建 restful API 。 JWT 代表 JSON Web Tokens 。 我们还将使用 API 为用户产品创建功能齐全的 CRUD 应用。

在使用跨平台应用程序时, API 是一个非常不错的选择。 除了网站,您的产品可能还有 Android 和 iOS 应用程序。 在这种情况下, API 也是同样出色的,因为您可以在不更改任何后端代码的情况下编写不同的前端。 使用 API 时,只需使用一些参数点击 GET , POST 或其他类型的请求,服务器就会返回 JSON (JavaScript Object Notation) 格式的一些数据,这些数据由客户端应用程序处理。

说明

我们先写下我们的应用程序详细信息和功能。 我们将使用 JWT 身份验证在 laravel 中使用 restful API 构建基本用户产品列表。

A User 将会使用以下功能

  • 注册并创建一个新帐户

  • 登录到他们的帐户

  • 注销和丢弃 token 并离开应用程序

  • 获取登录用户的详细信息

  • 检索可供用户使用的产品列表

  • 按 ID 查找特定产品

  • 将新产品添加到用户产品列表中

  • 编辑现有产品详细信息

  • 从用户列表中删除现有产品

A User 必填

  • name

  • email

  • password

A Product 必填

  • name

  • price

  • quantity

创建新的项目

通过运行下面的命令,我们就可以开始并创建新的 Laravel 项目。

composer create-project --prefer-dist laravel/laravel jwt

这会在名为 jwt 的目录下创建一个新的 Laravel 项目。

配置 JWT 扩展包

我们会使用 tymondesigns/jwt-auth 扩展包来让我们在 Laravel 中使用 JWT。

安装 tymon/jwt-auth 扩展包

让我们在这个 Laravel 应用中安装这个扩展包。如果您正在使用 Laravel 5.5 或以上版本,请运行以下命令来获取 dev-develop 版本的 JWT 包:

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

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

composer require tymon/jwt-auth

对于 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,请使用下面这条命令来发布配置文件:

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

对于之前 之前版本的 Laravel,那么应该运行下面这条命令:

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

上面的命令会生成 config/jwt.php 配置文件。除去注释部分,配置文件会像这样:

<?phpreturn [    'secret' => env('JWT_SECRET'),    'keys' => [        'public' => env('JWT_PUBLIC_KEY'),        'private' => env('JWT_PRIVATE_KEY'),        'passphrase' => env('JWT_PASSPHRASE'),    ],    'ttl' => env('JWT_TTL', 60),    'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),    'algo' => env('JWT_ALGO', 'HS256'),    'required_claims' => [        'iss',        'iat',        'exp',        'nbf',        'sub',        'jti',    ],    'persistent_claims' => [        // 'foo',        // 'bar',    ],    'lock_subject' => true,    'leeway' => env('JWT_LEEWAY', 0),    'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),    'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),    'decrypt_cookies' => false,    'providers' => [        'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,        'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,        'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,    ],];

生成 JWT 密钥

JWT 令牌通过一个加密的密钥来签发。对于 Laravel 5.5 或以上版本,运行下面的命令来生成密钥以便用于签发令牌。

php artisan jwt:secret

Laravel 版本低于 5.5 的则运行:

php artisan jwt:generate

这篇教程使用 Laravel 5.6。教程中接下来的步骤只在 5.5 和 5.6 中测试过。可能不适用于 Laravel 5.4 或以下版本。您可以阅读 针对旧版本 Laravel 的文档。

注册中间件

JWT 认证扩展包附带了允许我们使用的中间件。在 app/Http/Kernel.php 中注册 auth.jwt 中间件:

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

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

设置路由

开始之前,我们将为所有本教程讨论的点设置路由。打开 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');});

更新 User 模型

JWT 需要在 User 模型中实现 Tymon\JWTAuth\Contracts\JWTSubject 接口。 此接口需要实现两个方法 getJWTIdentifier 和 getJWTCustomClaims。使用以下内容更新 app/User.php 。

<?phpnamespace App;use Illuminate\Foundation\Auth\User as Authenticatable;use Illuminate\Notifications\Notifiable;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',    ];    /**     * Get the identifier that will be stored in the subject claim of the JWT.     *     * @return mixed     */    public function getJWTIdentifier()    {        return $this->getKey();    }    /**     * Return a key value array, containing any custom claims to be added to the JWT.     *     * @return array     */    public function getJWTCustomClaims()    {        return [];    }}

JWT 身份验证逻辑

让我们使用 JWT 身份验证在 laravel 中写 Restful API 的逻辑。

用户注册时需要姓名,邮箱和密码。那么,让我们创建一个表单请求来验证数据。通过运行以下命令创建名为 RegisterAuthRequest 的表单请求:

php artisan make:request RegisterAuthRequest

它将在 app/Http/Requests 目录下创建 RegisterAuthRequest.php 文件。将下面的代码黏贴至该文件中。

<?phpnamespace App\Http\Requests;use Illuminate\Foundation\Http\FormRequest;class RegisterAuthRequest extends FormRequest{    /**     * 确定是否授权用户发出此请求     *     * @return bool     */    public function authorize()    {        return true;    }    /**     * 获取应用于请求的验证规则     *     * @return array     */    public function rules()    {        return ['name' => 'required|string','email' => 'required|email|unique:users','password' => 'required|string|min:6|max:10'        ];    }}

运行以下命令创建一个新的 ApiController :

php artisan make:controller ApiController

这将会在 app/Http/Controllers 目录下创建 ApiController.php 文件。将下面的代码黏贴至该文件中。

<?phpnamespace 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(RegisterAuthRequest $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]);    }}

让我解释下上面的代码发生了什么。

在 register 方法中,我们接收了 RegisterAuthRequest 。使用请求中的数据创建用户。如果 loginAfterSignUp 属性为 true ,则注册后通过调用 login 方法为用户登录。否则,成功的响应则将伴随用户数据一起返回。

在 login 方法中,我们得到了请求的子集,其中只包含电子邮件和密码。以输入的值作为参数调用 JWTAuth::attempt() ,响应保存在一个变量中。如果从 attempt 方法中返回 false ,则返回一个失败响应。否则,将返回一个成功的响应。

在 logout 方法中,验证请求是否包含令牌验证。通过调用 invalidate 方法使令牌无效,并返回一个成功的响应。如果捕获到 JWTException 异常,则返回一个失败的响应。

在 getAuthUser 方法中,验证请求是否包含令牌字段。然后调用 authenticate 方法,该方法返回经过身份验证的用户。最后,返回带有用户的响应。

身份验证部分现在已经完成。

构建产品部分

要创建产品部分,我们需要 Product 模型,控制器和迁移文件。运行以下命令来创建 Product 模型,控制器和迁移文件。

php artisan make:model Product -mc

它会在 database/migrations 目录下创建一个新的数据库迁移文件 create_products_table.php,更改 up 方法。

public function up(){    Schema::create('products', function (Blueprint $table) {        $table->increments('id');        $table->integer('user_id');        $table->string('name');        $table->integer('price');        $table->integer('quantity');        $table->timestamps();        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');    });}

向 Product 模型中添加 fillable 属性。在 app 目录下打开 Product.php 文件并添加属性。

protected $fillable = [    'name', 'price', 'quantity'];

现在在 .env 文件中设置数据库凭证,并通过运行以下命令迁移数据库。

php artisan migrate

现在,我们必须在 User 模型中添加一个关系来检索相关产品。在 app/User.php 中添加以下方法。

public function products(){    return $this->hasMany(Product::class);}

在 app/Http/Controllers 目录下打开 ProductController.php 文件。在文件开头添加 use 指令覆盖上一个。

use App\Product;use Illuminate\Http\Request;use JWTAuth;

现在我们将实现五个方法。

index, 为经过身份认证的用户获取所有产品列表

show, 根据 ID 获取特定的产品

store, 将新产品存储到产品列表中

update, 根据 ID 更新产品详情

destroy, 根据 ID 从列表中删除产品

添加一个构造函数来获取经过身份认证的用户,并将其保存在 user 属性中。

protected $user;public function __construct(){    $this->user = JWTAuth::parseToken()->authenticate();}

parseToken 将解析来自请求的令牌, authenticate 通过令牌对用户进行身份验证。

让我们添加 index 方法。

public function index(){    return $this->user        ->products()        ->get(['name', 'price', 'quantity'])        ->toArray();}

上面的代码非常简单,我们只是使用 Eloquent 的方法获取所有的产品,然后将结果组成一个数组。最后,我们返回这个数组。Laravel 将自动将其转换为 JSON ,并创建一个为 200 成功的响应码。

继续实现 show 方法。

public function show($id){    $product = $this->user->products()->find($id);    if (!$product) {        return response()->json(['success' => false,'message' => 'Sorry, product with id ' . $id . ' cannot be found'        ], 400);    }    return $product;}

这个也非常容易理解。我们只需要根据 ID 找到该产品。如果产品不存在,则返回 400 故障响应。否则,将返回产品数组。

接下来是 store 方法

public function store(Request $request){    $this->validate($request, [        'name' => 'required',        'price' => 'required|integer',        'quantity' => 'required|integer'    ]);    $product = new Product();    $product->name = $request->name;    $product->price = $request->price;    $product->quantity = $request->quantity;    if ($this->user->products()->save($product))        return response()->json(['success' => true,'product' => $product        ]);    else        return response()->json(['success' => false,'message' => 'Sorry, product could not be added'        ], 500);}

在 store 方法中,验证请求中是否包含名称,价格和数量。然后,使用请求中的数据去创建一个新的产品模型。如果,产品成功的写入数据库,会返回成功响应,否则返回自定义的 500 失败响应。

实现 update 方法

public function update(Request $request, $id){    $product = $this->user->products()->find($id);    if (!$product) {        return response()->json(['success' => false,'message' => 'Sorry, product with id ' . $id . ' cannot be found'        ], 400);    }    $updated = $product->fill($request->all())        ->save();    if ($updated) {        return response()->json(['success' => true        ]);    } else {        return response()->json(['success' => false,'message' => 'Sorry, product could not be updated'        ], 500);    }}

在 update 方法中,我们通过 id 取得产品。如果产品不存在,返回一个 400 响应。然后,我们把请求中的数据使用 fill 方法填充到产品详情。更新产品模型并保存到数据库,如果记录成功更新,返回一个 200 成功响应,否则返回 500 内部服务器错误响应给客户端。

现在,让我们实现 destroy 方法。

public function destroy($id){    $product = $this->user->products()->find($id);    if (!$product) {        return response()->json(['success' => false,'message' => 'Sorry, product with id ' . $id . ' cannot be found'        ], 400);    }    if ($product->delete()) {        return response()->json(['success' => true        ]);    } else {        return response()->json(['success' => false,'message' => 'Product could not be deleted'        ], 500);    }}

在 destroy 方法中,我们根据 ID 获取产品,如果产品不存在,则返回 400 响应。然后我们删除产品后并根据删除操作的成功状态返回适当的响应。

控制器代码现在已经完成,完整的控制器代码在这。

测试

我们首先来测试身份认证。我们将使用 serve 命令在开发机上启动 Web 服务,你也可以使用虚拟主机代替。运行以下命令启动 Web 服务。

php artisan serve

它将监听 localhost:8000

为了测试 restful API's,我们使用 Postman。填写好请求体之后,我们请求一下 register 路由。

微信截图_20200509104149.png

发送请求,你将获得令牌。

微信截图_20200509104149.png

我们的用户现已注册并通过身份验证。我们可以发送另一个请求来检测 login 路由,结果会返回 200 和令牌。

微信截图_20200509104205.png

获取用户详情

微信截图_20200509104217.png

测试身份认证已完成。接下来测试产品部分,首先创建一个产品。

微信截图_20200509104231.png

现在,通过请求 index 方法获取产品。

微信截图_20200509104244.png

你可以测试其它路由,它们都将正常工作。

推荐教程:《Laravel教程》

以上就是使用Laravel集成JWT认证开发RestfulApi的详细内容,更多请关注其它相关文章!


  • 上一条:
    Laravel 7 扩展开发教程
    下一条:
    推荐下载量最高的100个Laravel扩展包
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • Laravel 11.14版本发布 - 新的字符串助手和ServeCommand改进(0个评论)
    • Laravel 11.12版本发布 - Artisan的`make`命令自动剪切`.php `扩展(0个评论)
    • Laravel的轻量型购物车扩展包:binafy/laravel-cart(0个评论)
    • Laravel 11.11版本发布 - 查看模型中的第三方关系:show(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-01
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客