使用 Laravel Passport 处理 API 认证

文件呢

我们将会学习使用 Laravel 的 Passport API OAuth 来创建一个验证系统。

第一步. 安装 Laravel

我们需要用以下命令来创建一个最新的 Laravel 应用,所以请打开终端执行:

laravel new auth

第二步. 安装 Laravel Passport 包

Laravel Passport 可以在几分钟内为你的应用实现一个完整的 OAuth2 服务器。

composer require laravel/passport

第三步. 运行数据库迁移

Passport 的迁移会创建你的应用用来存储客户端和 Access Token 的表。

php artisan migrate

第四步. 生成秘钥

此命令会创建秘钥以用来生成安全的 Access Token。除此之外,它也会创建用来生成 Access Token 的 personal accesspassword grant

php artisan passport:install

执行完毕后,将 Laravel\Passport\HasApiTokens trait 添加到你的 App\User 模型中。这个 trait 会为模型添加一系列助手函数用来验证用户的秘钥和作用域:

第五步 . Passport 配置

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use Notifiable, HasApiTokens;
}

接下来,你应该在 AuthServiceProvider 中的 boot 方法中调用 Passport::routes 方法。这个方法会注册必要的路由去颁发访问令牌,撤销访问令牌,客户端和个人令牌:

<?php

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}

最后,在 config/auth.php 配置文件中,你应该设置 api 权限认证守卫的 driver 选项为 passport。当需要权限认证的 API 请求进来时会告诉你的应用去使用 Passport's 的 TokenGuard

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

第六步. 添加 API 路由

Laravel 提供了 routes/api.php 文件来给我们编写 web 路由,因此在这个文件添加新的路由即可。

<?php

use Illuminate\Http\Request;

Route::group([
    'prefix' => 'auth'
], function () {
    Route::post('login', 'AuthController@login');
    Route::post('signup', 'AuthController@signup');

    Route::group([
      'middleware' => 'auth:api'
    ], function() {
        Route::get('logout', 'AuthController@logout');
        Route::get('user', 'AuthController@user');
    });
});

第七步: 创建控制器

最后一步我们必须创建新的控制器和 api 方法。因此我们先创建 AuthController 并且把代码写进去:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use App\User;

class AuthController extends Controller
{
    /**
     * Create user
     *
     * @param  [string] name
     * @param  [string] email
     * @param  [string] password
     * @param  [string] password_confirmation
     * @return [string] message
     */
    public function signup(Request $request)
    {
        $request->validate([
            'name' => 'required|string',
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed'
        ]);

        $user = new User([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password)
        ]);

        $user->save();

        return response()->json([
            'message' => 'Successfully created user!'
        ], 201);
    }

    /**
     * Login user and create token
     *
     * @param  [string] email
     * @param  [string] password
     * @param  [boolean] remember_me
     * @return [string] access_token
     * @return [string] token_type
     * @return [string] expires_at
     */
    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|string|email',
            'password' => 'required|string',
            'remember_me' => 'boolean'
        ]);

        $credentials = request(['email', 'password']);

        if(!Auth::attempt($credentials))
            return response()->json([
                'message' => 'Unauthorized'
            ], 401);

        $user = $request->user();

        $tokenResult = $user->createToken('Personal Access Token');
        $token = $tokenResult->token;

        if ($request->remember_me)
            $token->expires_at = Carbon::now()->addWeeks(1);

        $token->save();

        return response()->json([
            'access_token' => $tokenResult->accessToken,
            'token_type' => 'Bearer',
            'expires_at' => Carbon::parse(
                $tokenResult->token->expires_at
            )->toDateTimeString()
        ]);
    }

    /**
     * Logout user (Revoke the token)
     *
     * @return [string] message
     */
    public function logout(Request $request)
    {
        $request->user()->token()->revoke();

        return response()->json([
            'message' => 'Successfully logged out'
        ]);
    }

    /**
     * Get the authenticated User
     *
     * @return [json] user object
     */
    public function user(Request $request)
    {
        return response()->json($request->user());
    }
}

现在我们已经准备好运行我们的示例了,运行下面的命令以快速运行:

php artisan serve

测试

现在,我们可以使用 REST 客户端工具来简化测试,例如 Postman。我执行测试你可以看见以下的截图。

你要为这个 API 设置以下两个头信息:

Content-Type: application/json
X-Requested-With: XMLHttpRequest

file

注册

file

登录

file

登出

file

用户

file


感谢阅读!

资源

引用

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://medium.com/modulr/create-api-aut...

译文地址:https://learnku.com/laravel/t/22586

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 32
Toiu

挑个刺. 注册的时候是不是应该直接登录了并返回token..(当然这并不是本帖的重点:smile: )

5年前 评论
盖伦有个打不溜 4年前
小李世界 4年前

感谢作者,我本来使用的是JWT登录方式,后来发现了PassPort,遂使用文章内的方法进行了实现,其他一切都已走通,但是这段代码执行的效果有差异,还望老师给予解惑:

$user = $request->user();
$token = $user->createToken('Access Token')->accessToken;
return $token;

文中的执行效果正确得到了breaer加密方式的access_token,然而我的执行效果得到了一个数组,内容为:

{
    "name": "Access Token",
    "abilities": [
        "*"
    ],
    "tokenable_id": 1,
    "tokenable_type": "App\\Models\\User",
    "updated_at": "2020-11-29T06:02:53.000000Z",
    "created_at": "2020-11-29T06:02:53.000000Z",
    "id": 8
}

不知道是何缘故,望有识之士给予解答

2020.11.29 更新

找到原因了,原来我使用的并非passport方式,而是sanctum方式,具体修改代码如下:
App\Models\User.php

use Laravel\Sanctum\HasApiTokens;
// 修改为
use Laravel\Passport\HasApiTokens;
3年前 评论

正好在做登录认证这一块就看到了这篇文章,Good

5年前 评论
KayuHo

第五步下面的 User 模型应该放到第四步的最后吧,位置放错了。

5年前 评论

login方法的createToken就是请求oauth\token嘛

5年前 评论
luci 4年前
陈先生 2年前

大佬,API 多端多表passport如何处理呢?官档写的不能很好理解。

4年前 评论

你这样生成的 Personal Access Token 的过期时间 还是 原来的 1年. 真正的过期时间并没有变化.

4年前 评论

比只有用 jwt 来得简单啊,对新手很友好,不错。

4年前 评论

想问下,token通过header传过去后,没有看到在代码中再次验证,这个地方不太明白。或者说,如果我通过post方式传token过去,那应该如何验证token呢?

4年前 评论
ouer1994 4年前
qiuyuhome

有个问题不太明白. 请指教.
按照文中的逻辑, 同一个用户, 登陆几次, 就会创建几个 token. 这样子是对的么? 如果是对的, 那 oauth_access_tokens 岂不是越来越大.

4年前 评论
小李世界 4年前
ifui 3年前

只有经过了 auth:api 中间件的路由才能使用 request()->user() 获取到用户信息;
那如果路由没有走 auth:api 中间件验证,在控制器中怎么获取到用户信息呢?请求的 header 中已经携带了 token 信息;

Route::group( ['middleware' => 'auth:api'] , function () {
Route::get(' test ', function() {
dump( request()->user() ); // 经过了 auth:api 中间件的路由能获取到用户信息
});
});

Route::get(' test ', function() {
dump( request()->user() ); // 没有走 auth:api 中间件验证的路由 不 能获取到用户信息,但是 header 中有携带 token 信息
});

有这样的应用场景;网站首页有文章列表,游客也能访问首页,所以获取首页数据的接口路由是不走 auth:api 中间件的;但是当用户登录后返回到首页,首页接口获取某些数据时是要拿 user 信息的,比如判断用户是否关注、点赞某篇文章,而由于接口路由没有走中间件,改怎么获取用户数据呢?

4年前 评论
Suckbiao (作者) 4年前
相伟 3年前

login方法中使用Auth::attempt()进行登录没有问题,但是如果使用Auth::guard("api")->attempt()会报错:

Method Illuminate\\Auth\\RequestGuard::attempt does not exist.

有没有大神可以解答一下是为什么 :grin:

4年前 评论
yangonce 3年前
Taurus (作者) 3年前
feamac 3年前
wZzz_98 2年前
Leesinyii 1年前

为啥我的账号密码正确,一直返回false啊,求大佬解答

4年前 评论

我有个问题,前端怎么保存密钥呢?业界都是怎么做的呢?

4年前 评论
ifui 3年前

login 获取一个新的access_token 并且有效期设置成三分钟
三分钟后还能通过这个access_token 访问user获取到用户信息,,就没看懂这个过期时间...

3年前 评论

登录后接口为什么不用返回 refresh_token ,不用做刷新 token 机制吗?

3年前 评论
Alexander- 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!