作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Layo Folaranmi的头像

Layo Folaranmi

Layo是一位专注于全栈web开发的软件工程师, 具有丰富的PHP经验, JavaScript, Laravel, and Vue.js.

工作经验

7

Share

在开发web应用程序时,将其分成两层通常是一个好主意. 中间层API与数据库交互, web层通常由前端SPA或MPA组成. This way, web应用程序是松散耦合的, 使其在长期运行中更易于管理和调试.

创建API时, 在无状态API上下文中设置身份验证和状态似乎有些问题.

在本文中, 我们将学习如何使用Laravel和Passport在API中实现完整的用户身份验证和简单形式的访问控制. 你应该有与……共事的经验 Laravel 因为这不是一个入门教程.

安装先决条件:

  • PHP 7+, MySQL和Apache(想要同时安装这三个的开发人员可以使用 XAMPP.)
  • Composer
  • Laravel 7
  • Laravel护照. 因为api通常是无状态的,不使用会话, 我们通常使用令牌来保持请求之间的状态. Laravel使用Passport库实现了一个完整的OAuth2服务器,我们可以在API中使用它进行身份验证.
  • Postman、cURL或Insomnia来测试api——这取决于个人偏好
  • 您选择的文本编辑器
  • Laravel助手(用于Laravel 6.0及以上)-安装Laravel和Passport后,只需运行:
作曲家需要laravel/助手

安装了上述组件后,我们就可以开始了. 控件来设置数据库连接 .env file.

Laravel护照教程,第1步:为虚拟请求添加控制器和模型

首先,我们将为虚拟请求创建一个控制器和模型. 该模型在本教程中不会有太大用处, 它只是给出了控制器要操作的数据的概念.

在创建模型和控制器之前,我们需要创建一个迁移. 在终端机里 cmd.exe 窗口,如果你使用的是Windows-run:

create_articles_table——create=articles

Now, go to the 数据库/迁移 文件夹并打开文件名类似于的文件 xxxx_xx_xx_xxxxxx_create_articles_table.php.

In the up 类的函数,我们这样写:

Schema::create('articles', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->string('body');
    $table->integer('user_id');
    $table->timestamps();
});

接下来,我们将创建一个 Article model. 要做到这一点,运行:

php工匠制作:模型文章 

然后我们创建 ArticleController 控制器通过运行:

ArticleController——resource . php

接下来,我们将编辑该文件 应用程序/供应商/ AppServiceProvider.php and import the 照亮\ \外墙\模式的支持 类中添加:

使用说明\ \外墙\模式的支持

…放到文件顶部导入的底部.

Then, in the boot 函数,我们会这样写:

模式:defaultStringLength (191);

完成所有这些之后,我们可以运行:

PHP工匠迁移

来应用我们上面创建的迁移.

Laravel护照教程,第2步:创建中间件的必要部分

在这里,我们将添加API工作所必需的中间件.

JSON Responses

需要的第一块是 ForceJsonResponse 中间件,它将自动将所有响应转换为JSON.

要做到这一点,运行:

中间件ForceJsonResponse

这是中间件的句柄函数 应用程序/ Http /中间件/ ForceJsonReponse.php:

函数handle($request, close $next)
{
    $request->headers->set('Accept', 'application/json');
    请求返回一美元(美元);
}

接下来,我们将把中间件添加到 应用程序/ Http /内核.php file in the routeMiddleware美元 array:

'json.response' => Http \中间件\ \ App \ ForceJsonResponse::类,

然后,我们也会把它加到 $middleware 数组在同一个文件中:

Http \中间件\ \ App \ ForceJsonResponse::类,

这样可以确保 ForceJsonResponse 中间件在每个请求上运行.

跨域资源共享

让我们的消费者 Laravel REST API 要从不同的原点访问它,我们必须设置CORS. 为此,我们将创建一个名为 Cors.

在终端或命令提示符中, cd 进入项目根目录并运行:

php工匠制作中间件

Then, in 应用程序/ Http /中间件/歌珥.php,添加以下代码:

函数handle($request, close $next)
{
    返回下一美元(美元请求)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        ->header('Access-Control-Allow-Headers', “X-Requested-With, Content-Type, X-Token-Auth, 授权”);
}

要加载这个中间件,我们需要添加一行 应用程序/ Http /内核.php’s routeMiddleware美元 array:

'cors' => Http \中间件\ \ App \歌珥::类,

我们还要把它加到 $middleware 数组,就像我们为之前的中间件所做的那样:

Http \中间件\ \ App \歌珥::类,

之后,我们将把这个路由组附加到 routes/api.php:

Route::group(['middleware' => ['cors', 'json.响应']],函数(){
    // ...
});

我们所有的API路由都将进入这个函数,我们将在下面看到.

Laravel护照教程,第3步:为API创建用户身份验证控制器

现在我们要创建身份验证控制器 login and register functions.

首先,我们运行:

php artisan make:controller Auth/ApiAuthController

现在我们将导入一些类到文件中 app / Http /控制器/认证/ ApiAuthController.php. 类的创建中将使用这些类 login and register functions. 我们将通过添加以下内容来导入这些类:

use App\User;
使用说明\ \外墙\散列的支持;
使用说明\ \外墙\验证器的支持;
使用说明\ \ Str的支持;

到控制器的顶部.

现在,要为我们的用户添加Laravel API认证,我们将创建 login, logout, and register (注册)函数在同一个文件中.

The register 函数看起来像这样:

注册(请求){
    $validator = Validator::make($request->all(), [
        'name' => 'required|string|max:255',
        'email' => 'required|string|email|max:255|unique:users',
        'password' => 'required|string|min:6|confirmed',
    ]);
    if ($validator->fails())
    {
        return response(['errors'=>$validator->errors()->all()], 422);
    }
    请求['密码']=散列:美元:使($请求['密码']);
    $request['remember_token'] = Str::random(10);
    $user = User::create($request->toArray());
    $token = $user->createToken('Laravel Password Grant Client')->accessToken;
    $response = ['token' => $token];
    返回响应($response, 200);
}

The login 函数是这样的:

公共函数登录(请求$请求){
    $validator = Validator::make($request->all(), [
        'email' => 'required|string|email|max:255',
        'password' => 'required|string|min:6|confirmed',
    ]);
    if ($validator->fails())
    {
        return response(['errors'=>$validator->errors()->all()], 422);
    }
    $user = User::where('email', $request->email)->first();
    if ($user) {
        if (Hash::check($request->password, $user->password)) {
            $token = $user->createToken('Laravel Password Grant Client')->accessToken;
            $response = ['token' => $token];
            返回响应($response, 200);
        } else {
            $response = ["message" => "Password mismatch"];
            返回响应($response, 422);
        }
    } else {
        $response = ["message" =>'User does not exist'];
        返回响应($response, 422);
    }
}

最后, logout function:

公共函数注销(请求$请求){
    $token = $request->user()->token();
    $token->revoke();
    $response = ['message' => 'You have been successfully logged out!'];
    返回响应($response, 200);
}

之后,我们需要添加 login, register, and logout 函数到我们的路线,I.e., 在路由组内 已经在API中:

Route::group(['middleware' => ['cors', 'json.响应']],函数(){

    // ...

    //公共路由
    Route::post('/login', 'Auth\ApiAuthController@login')->name('login.api');
    Route::post('/register','Auth\ApiAuthController@register')->name('register.api');
    Route::post('/logout', 'Auth\ApiAuthController@logout')->name('logout.api');

    // ...

});

最后,我们需要添加 HasApiToken trait to the User model. Navigate to app/User 确保你有:

使用HasApiTokens, Notifiable;

在班上名列前茅.

我们目前所拥有的……

如果我们启动应用程序服务器- i.e., run PHP工匠服务-然后试着发送一个 GET 请求航路 /api/user,我们应该收到这样的信息:

{
    “消息”:“未经身份验证的请求."
}

这是因为我们没有被认证 访问那条路线. 为了使您选择的一些路线受到保护,我们可以将它们添加到 routes/api.php just after the Route::post lines:

Route::middleware('auth:api')->group(function () {
    //我们要保护的路由放在这里
});

在继续之前,我们将向 auth:api 因为Laravel使用令牌来注销用户——这个令牌不能从外部访问 auth:api middleware. Our public 路由是这样的:

Route::group(['middleware' => ['cors', 'json.响应']],函数(){

    // ...

    //公共路由
    Route::post('/login', 'Auth\ApiAuthController@login')->name('login.api');
    Route::post('/register', 'Auth\ApiAuthController@register')->name('register.api');

    // ...

});

Our protected 另一方面,路线看起来是这样的:

Route::middleware('auth:api')->group(function () {
    //我们要保护的路由放在这里
    Route::post('/logout', 'Auth\ApiAuthController@logout')->name('logout.api');
});

现在我们将导航到 ArticleController we created in 应用程序/ Http /控制器/ ArticleController.php and delete the create and edit 类中的方法. 之后,我们将添加以下代码片段,稍微编辑一下,到每个剩下的函数:

$response = ['message' =>  ' function'];
返回响应($response, 200);

We’ll fill in as appropriate. 例如, update 函数将以这个作为它的主体:

$response = ['message' => 'update function'];
返回响应($response, 200);

手工Laravel认证测试:创建用户

要注册一个用户,我们将发送一个 POST request to /api/register 使用以下参数: name, email (必须是唯一的) password, and password_confirmation.

使用Postman发送POST请求到/api/register的截图.

创建用户时, API将返回一个令牌, 我们将在以后的请求中使用它作为身份验证的手段.

登录时,我们会发送一个 POST request to /api/login. 如果我们的凭据是正确的,我们也将通过这种方式从Laravel登录API获得一个令牌.

使用Postman发送POST请求到/api/login的截图.

当我们想要访问受保护的路由时,我们可以使用从该请求返回的授权令牌. In Postman, “授权”选项卡有一个下拉菜单,可以将类型设置为“承载令牌”,之后,令牌可以进入令牌字段.

这个过程非常相似 Insomnia.

cURL用户可以通过传递参数来完成相同的操作 -H "Authorization: Bearer ", where 授权令牌是否从登录或注册响应中给出.

As with cURL, 如果开发人员计划使用axios或类似的库来使用API, 他们可以加上 Authorization 带值头 Bearer .

Laravel护照教程,步骤4:创建密码重置功能

现在基本身份验证已经完成,接下来是设置密码重置功能的时候了.

为此,我们可以选择创建一个 api_auth 控制器目录, 创建新的自定义控制器, and implement the function; or we can edit the auth controllers that we can generate with Laravel. 在本例中,我们将编辑认证控制器,因为整个应用程序是一个API.

首先,我们将运行以下命令生成认证控制器:

编写器需要laravel/ui
PHP工匠UI值——auth

我们将把这个类编辑进去 app / Http /控制器/认证/ ForgotPasswordController.php,加上这两种方法:

sendResetLinkResponse(请求$ Request, $response)
{
    $response = ['message' => "Password reset email sent"];
    返回响应($response, 200);
}
sendResetLinkFailedResponse(请求$ Request, $response)
{
    $response = "邮件无法发送到此邮箱";
    返回响应($response, 500);
}

接下来,我们需要设置实际重置密码的控制器,因此我们将导航到 app / Http /控制器/认证/ ResetPasswordController.php 并像这样覆盖默认函数:

resetPassword($user, $password)
{
    $user->password = Hash::make($password);
    $user->save();
    事件(新PasswordReset(用户)美元);
}
sendResetResponse(请求$ Request, $response)
{
    $response = ['message' => "Password reset successful"];
    返回响应($response, 200);
}
sendResetFailedResponse(请求$ Request, $response)
{
    $response = "令牌无效";
    返回响应($response, 401);
}

我们还需要在控制器中导入一些类:

使用照亮\ Auth \ \ PasswordReset事件;
使用说明\ Http \请求;
使用说明\ \外墙\散列的支持;

到控制器的顶部.

我们需要修改使用的电子邮件通知, too, 因为Laravel自带的邮件通知不使用API令牌进行授权. 我们可以创建一个新的 app /通知 通过运行命令:

MailResetPasswordNotification . php 

我们需要编辑这个文件 应用程序/通知/ MailResetPasswordNotification.php 看起来像这样:

pageUrl = 'localhost:8080';
            //我们可以在这里设置任何我们想要的,或者使用 .设置环境变量
        }
    /**
    *获取通知的传递渠道.
    *
    * @param mixed $ notiffiable
    * @return array
    */
    通过($notifiable)实现公共功能
    {
        返回(“邮件”);
    }
    /**
    *获取通知的邮件表示.
    *
    * @param mixed $ notiffiable
    * @return \Illuminate\Notifications\Messages\MailMessage
    */
    公共函数toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $this->token);
        }
        返回(new MailMessage)
            ->subject(Lang::getFromJson('Reset application Password'))
            ->line(Lang::getFromJson('You are receiving this email because we received a password reset request for your account.'))
            ->action(Lang::getFromJson('Reset Password'), $this->pageUrl."?token=".$this->token)
            ->line(Lang::getFromJson('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.users.expire')]))
            ->line(Lang::getFromJson('If you did not request a password reset, no further action is required.'));
    }
    /**
    *获取通知的数组表示形式.
    *
    * @param mixed $ notiffiable
    * @return array
    */
    公共函数toArray($notifiable)
    {
        return [
            //
        ];
    }
}

要使用这个新通知,我们需要重写 sendPasswordResetNotification method that User 继承自 Authenticatable class. 我们要做的就是把这个加上 app/User.php:

sendPasswordResetNotification($token)
{
    $this->notify(new \App\Notifications\MailResetPasswordNotification($token));
}

有了功能正常的邮件设置,此时通知应该可以工作了.

现在剩下的就是用户访问控制了.

Laravel护照教程,第5步:创建访问控制中间件

在创建访问控制中间件之前,我们需要更新 user 表中有一个名为 type, 用哪个来确定用户级别:类型0是普通用户, 类型1是管理员, 第二种是超级管理员.

To update the user 表中,我们必须运行以下命令创建一个迁移:

update_users_table_to_include_type——table=users

在新创建的表单文件中 数据库/迁移/ _update_users_table(时间戳).php,我们需要更新 up and down 函数来添加和删除 type 列,分别是:

公共功能up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->integer('type');
    });
}
/**
 *反向迁移.
 *
 * @return void
 */
公共函数down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropIfExists('type');
    });
}

接下来,我们跑步 PHP工匠迁移. 完成后,我们需要编辑 register 函数中的 ApiAuthController.php 文件,在行之前添加 $user = User::create($request->toArray());:

$request['type'] = $request['type'] ? $request['type']: 0;

同样,我们需要将这一行添加到 $validator array:

'type' => 'integer',

这两个编辑中的第一个将使所有注册用户默认为“普通用户”.e.,如果未输入用户类型.

访问控制中间件本身

现在我们可以创建两个中间件用于访问控制:一个用于管理员,另一个用于超级管理员.

So we’ll run:

中间件AdminAuth
中间件SuperAdminAuth

首先,我们将导航到 应用程序/ Http /中间件/ AdminAuth.php and import 照亮\ \外墙\身份验证的支持,然后编辑 handle 函数如下:

函数handle($request, close $next)
{
    if (Auth::guard('api')->check() && $request->user()->type >= 1) {
        请求返回一美元(美元);
    } else {
        $message = ["message" => "Permission Denied"];
        返回响应($message, 401);
    }
}

我们还需要编辑 handle function in 应用程序/ Http /中间件/ SuperAdminAuth.php:

函数handle($request, close $next)
{
    if (Auth::guard('api')->check() && $request->user()->type >= 2) {
        请求返回一美元(美元);
    } else {
        $message = ["message" => "Permission Denied"];
        返回响应($message, 401);
    }
}

您还应该导入 Auth 类在两个文件的顶部添加:

使用说明\ \外墙\身份验证的支持;

在那里找到的进口产品的底部.

为了使用我们的新中间件,我们将在内核i中引用这两个类.e., in 应用程序/ Http /内核.php-通过将以下行添加到 routeMiddleware美元 array:

'api.admin' => \App\Http\Middleware\AdminAuth::class,
'api.superAdmin' => \App\Http\Middleware\SuperAdminAuth::class,

如果开发人员想在给定的路由中使用中间件, 你只需要把它添加到route函数中,就像这样:

Route::post('route','Controller@method')->middleware('');

在这种情况下可以 api.admin, api.superAdmin, etc.,视情况而定.

这就是创建中间件所需要的全部内容.

把它们放在一起

为了测试我们的身份验证和访问控制是否有效, 还有一些额外的步骤需要完成.

测试Laravel认证和访问控制:步骤1

我们需要修改 ArticleController’s index 函数并注册路由. (在实际项目中,我们将使用PHPUnit并将其作为自动化测试的一部分. 在这里,我们手动添加一条用于测试的路由——之后可以删除它.)

我们将导航到 ArticleController controller at 应用程序/ Http /控制器/ ArticleController and modify the index 函数看起来像这样:

公共功能索引()
{
    $response = ['message' => 'article index'];
    返回响应($response, 200);

}

接下来,我们将在路由中注册这个函数 routes/api.php 文件和附加这个:

Route::middleware('auth:api')->group(function () {
Route::get('/articles', 'ArticleController@index')->name('articles');
});

测试Laravel认证和访问控制:步骤2

现在我们可以尝试在没有身份验证令牌的情况下访问路由. 我们应该收到一个身份验证错误.

使用Postman发送GET请求到/api/articles的截图, 在响应中收到一条消息“未经验证”.

测试Laravel认证和访问控制:步骤3

我们还可以尝试使用授权令牌(本文前面通过注册或登录获得的令牌)访问相同的路由。.

有时,这可能会导致类似这样的错误:

未知列'api_token'在'where子句' (SQL: select * from ' users 'where 'api_token' = . ...

从使用邮差获取api/文章路由的未知列错误的截图.

如果发生这种情况,开发者应该这样做 make sure 运行护照迁移并且有 (“警卫”)(“api”)(“司机”) set to passport in config/auth.php:

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

    'api' => [ 
        'driver' => 'passport', 
        'provider' => 'users', 
    ], 
],

之后,配置缓存也需要更新.

一旦修好,我们就能进入路线了.

使用Postman向/api/articles发送GET请求的截图,带有正常的JSON响应.

测试Laravel认证和访问控制:步骤4

是时候测试访问控制了. Let’s append ->middleware('api.admin') 到文章路由,看起来是这样的:

Route::get('/articles', 'ArticleController@index')->middleware('api.admin')->name('articles');

我们这样做是为了使新创建的用户自动分配类型0,正如我们可以通过 api/user route.

使用Postman向/api/user发送GET请求的截图. 响应包含一个ID, name, email, 空邮件验证时间戳, 填写已创建和更新的时间戳, and a type.

因此,我们应该得到一个错误,试图访问 articles 端点作为这样的用户.

使用Postman发送GET请求到/api/articles的截图, 返回Permission Denied JSON响应.

为了进行测试,让我们修改数据库中的用户,使其具有 type of 1. 验证该更改之后 api/user 路线再来一次,我们准备再试一次 GET the /articles/ route.

使用Postman作为larvel认证的用户向/api/articles发送GET请求的截图, 和之前的请求一样, 除了这个的响应时间是1,280毫秒而不是890毫秒.

效果很好.

开发更复杂应用程序的开发人员应该注意到,适当的访问控制不会这么简单. 在这种情况下,其他第三方应用程序或Laravel的 盖茨和政策 可以用来实现自定义用户访问控制吗. 在本系列的第2部分中,我们将介绍更健壮和灵活的访问控制解决方案.

Laravel API认证:我们所学到的

在这个Laravel护照教程中,我们讨论了:

  1. 创建一个虚拟控制器和模型,以便在测试Laravel护照示例时使用.
  2. 创建使API顺利运行所需的中间件, 寻址CORS并强制API始终返回JSON响应.
  3. 设置基本的Laravel API认证:注册、登录和注销.
  4. 基于Laravel的默认设置设置“密码重置”功能.
  5. 创建访问控制中间件,为不同的路由添加用户授权权限级别.

这些都是任何在这个领域工作的人的基本技能 Laravel开发服务. 读者会发现最后的结果 这个GitHub仓库 现在应该可以很好地使用Laravel实现身份验证. 我们期待您的评论.

了解基本知识

  • 什么是Laravel护照?

    Laravel护照是一个OAuth.0服务器实现API认证使用Laravel. 因为令牌通常用于API身份验证, Laravel护照提供了一种在OAuth上实现令牌授权的简单而安全的方法.0 server.

  • Laravel护照的用途是什么?

    Laravel护照是一个用于在Laravel REST API中实现身份验证的包.

  • Laravel护照安全吗?

    Laravel护照是一个OAuth.0服务器实现无状态身份验证. OAuth 2.0是最新的OAuth协议,是的,它是安全的.

  • 什么是无状态API?

    在无状态API中,对它的每个请求都是完全隔离的,每个请求的响应完全依赖于请求本身. 这与有状态应用程序不同, 每个请求的响应依赖于服务器和请求的“状态”.

就这一主题咨询作者或专家.
预约电话
Layo Folaranmi的头像
Layo Folaranmi

Located in Lagos, Nigeria

Member since March 1, 2019

作者简介

Layo是一位专注于全栈web开发的软件工程师, 具有丰富的PHP经验, JavaScript, Laravel, and Vue.js.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

工作经验

7

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal开发者

加入总冠军® community.