在本教程中,我们将通过使用Sanctum
应用程序开发完整的Laravel 11 REST API
身份验证以及简单的分步指南来了解使用Sanctum
身份验证的Laravel 11 REST API
。
我们将从头开始学习API
、REST API
和Laravel Sanctum
,并创建一个示例API
。
API
是什么?
API
(应用程序编程接口)只是两个或多个计算机程序之间的一种通信方式。API
还用于Web
和移动应用程序开发;因此,构建REST API
对于任何Web
和移动应用程序开发人员来说都非常重要。
Laravel Sanctum
是什么?
Laravel Sanctum
是Laravel
应用程序的API
身份验证包,为单页应用程序(SPA)、移动应用程序和其他API
驱动的项目提供轻量级、简单易用的身份验证系统。它使用JSON Web
令牌(JWT) 或API
令牌提供基于令牌的身份验证,从而实现安全身份验证,而无需传统基于会话的身份验证的开销。Sanctum
简化了令牌身份验证的设置,使开发人员能够专注于构建他们的应用程序,而不是处理身份验证的复杂性。
我们将使用Laravel Sanctum
,这是一个身份验证系统包,用于为SPA
(单页应用程序)开发简单的API
,这些API
通常通过React JS
、Angular
或Vue JS
构建。
在此示例中,我们将安装Laravel 11
应用程序。然后,我们将安装用于API
身份验证的Sanctum composer
包。之后,我们将创建用于用户身份验证的注册和登录API
。然后,我们将创建一个产品REST API
,并且您必须使用用户令牌进行身份验证。因此,让我们按照以下步骤逐步完成此示例:
按照以下步骤在Laravel 11
应用程序中创建RESTful API
完整示例。
第一步 安装Laravel 11
如果已经安装可以忽略;如果您尚未创建Laravel
应用程序,则可以继续执行以下命令:
composer create-project laravel/laravel example-app
第二步 安装组件Sanctum API
包
在Laravel 11
中,默认情况下,我们没有api.php
路由文件。因此,您只需要运行以下命令即可安装带有api.php
文件的Sanctum
。
php artisan install:api
第三步 配制Sanctum
文件
在此步骤中,我们必须配置三个位置:模型、服务提供商和身份验证配置文件。因此,您只需要在这些文件中进行以下更改:
在模型中,我们添加了Sanctum
的HasApiTokens
类。
在auth.php
中,我们添加了API
身份验证配置。
app/Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
第四步 添加Product Table
和Product
模型
接下来,我们需要使用laravel artisan
命令为products
表创建迁移。因此,首先,执行以下命令:
php artisan make:migration create_products_table
执行此命令后,您将在以下路径database/migrations
中找到一个文件,并且您必须将以下代码放入迁移文件中才能创建products
表。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('detail');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
创建迁移后,我们需要通过以下命令运行上述迁移:
php artisan migrate
创建Product
表后,应为产品创建产品模型。因此,首先,在此路径app/Models/Product.php
创建一个文件,并将以下内容放入item.php
文件中:
app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'detail'
];
}
第五步创建API
路由
在此步骤中,我们将为login
、register
和roducts
REST API
创建API
路由。因此,让我们在该文件中添加一个新路由。
routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::controller(App\Http\Controllers\Api\RegisterController::class)->group(function(){
Route::post('register', 'register');
Route::post('login', 'login');
});
Route::middleware('auth:sanctum')->group( function () {
Route::resource('products', App\Http\Controllers\Api\ProductController::class);
});
第六步创建控制器Controller
文件
在下一步中,我们创建了一个名为Controller
、ProductController
和RegisterController
的新控制器。我在Controllers
文件夹中创建了一个名为API
的新文件夹,因为我们将有单独的API
控制器。因此,让我们创建两个控制器。
app/Http/Controllers/Api/Controller.php
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
class Controller
{
/**
* success response method.
*
* @return \Illuminate\Http\Response
*/
public function sendResponse($result, $message)
{
$response = [
'status' => 1,
'data' => $result,
'message' => $message,
];
return response()->json($response, 200);
}
/**
* return error response.
*
* @return \Illuminate\Http\Response
*/
public function sendError($error, $errorMessages = [], $code = 404)
{
$response = [
'status' => 1,
'message' => $error,
];
if(!empty($errorMessages)){
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
}
app/Http/Controllers/Api/RegisterController.php
<?php
namespace App\Http\Controllers\Api;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Validator;
class RegisterController extends Controller
{
/**
* Register api
*
* @return \Illuminate\Http\Response
*/
public function register(Request $request): JsonResponse
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
'c_password' => 'required|same:password',
]);
if($validator->fails()){
return $this->sendError('Validation Error.', $validator->errors());
}
$input = $request->all();
$input['password'] = bcrypt($input['password']);
$user = User::create($input);
$success['token'] = $user->createToken('MyApp')->plainTextToken;
$success['name'] = $user->name;
return $this->sendResponse($success, 'User register successfully.');
}
/**
* Login api
*
* @return \Illuminate\Http\Response
*/
public function login(Request $request): JsonResponse
{
if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')->plainTextToken;
$success['name'] = $user->name;
return $this->sendResponse($success, 'User login successfully.');
}
else{
return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
}
}
}
app/Http/Controllers/Api/ProductController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Resources\ProductResource;
use App\Models\Product;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Validator;
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(): JsonResponse
{
$products = Product::all();
return $this->sendResponse(ProductResource::collection($products), 'Products retrieved successfully.');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request): JsonResponse
{
$input = $request->all();
$validator = Validator::make($input, [
'name' => 'required',
'detail' => 'required'
]);
if($validator->fails()){
return $this->sendError('Validation Error.', $validator->errors());
}
$product = Product::create($input);
return $this->sendResponse(new ProductResource($product), 'Product created successfully.');
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id): JsonResponse
{
$product = Product::find($id);
if (is_null($product)) {
return $this->sendError('Product not found.');
}
return $this->sendResponse(new ProductResource($product), 'Product retrieved successfully.');
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Product $product): JsonResponse
{
$input = $request->all();
$validator = Validator::make($input, [
'name' => 'required',
'detail' => 'required'
]);
if($validator->fails()){
return $this->sendError('Validation Error.', $validator->errors());
}
$product->name = $input['name'];
$product->detail = $input['detail'];
$product->save();
return $this->sendResponse(new ProductResource($product), 'Product updated successfully.');
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Product $product): JsonResponse
{
$product->delete();
return $this->sendResponse([], 'Product deleted successfully.');
}
}
第七步 创建Eloquent API Resources
资源
这是在Laravel 11
中创建REST API
的一个非常重要的步骤。您可以将Eloquent API
资源与API
一起使用。它将帮助您保持模型对象的相同响应布局。我们在ProductController
文件中使用了它。现在,我们必须使用以下命令创建它:
php artisan make:resource ProductResource
现在,已创建一个新文件,其中包含以下路径中的新文件夹:
app/Http/Resources/ProductResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'detail' => $this->detail,
'created_at' => $this->created_at->format('d/m/Y'),
'updated_at' => $this->updated_at->format('d/m/Y'),
];
}
}
第八步 为了API
结果统一,把异常进行改造如下:
<?php
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
// 以下可据实际做相应调整
$exceptions->render(function(AuthenticationException|RouteNotFoundException|HttpException|ErrorException $exception, Request $request) {
if ($request->is('api/*')) {
$statusCode = match (true) {
$exception instanceof RouteNotFoundException => 404,
$exception instanceof AuthenticationException => 401,
default => 200
};
$status = match (true) {
500 > $statusCode && $statusCode > 400 => 4,
default => 1
};
return response()->json(
[
'status' => $status,
'message' => $exception->getMessage()
],
$statusCode
);
}
});
})->create();
所有必需的步骤都已完成。现在,您必须键入以下给定的命令并按回车键以运行Laravel
应用程序:
php artisan serve
现在,转到您的Postman
并检查以下API
。
请确保在详细信息API
中,我们将使用如下所示的请求头信息,登陆和注册除外:
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
]
实例效果
以下是运行实例截图。
Register API
: 请求方式:GET
, URL
地址: http://localhost:8000/api/register
Login API
: 请求方式:GET
, URL
地址: http://localhost:8000/api/login
Product List API
: 请求方式: GET
, URL
地址: http://localhost:8000/api/products
Product Create API
: 请求方式: POST
, URL
地址: http://localhost:8000/api/products
Product Show API
: 请求方式: GET
, URL
地址: http://localhost:8000/api/products/{id}
Product Update API
: 请求方式: PUT
, URL
地址: http://localhost:8000/api/products/{id}
Product Delete API
: 请求方式: DELETE
, URL
地址: http://localhost:8000/api/products/{id}