Laravel 5.4 中使用 Laravel Passport 构建后端授权认证 API


转载自:https://laravel-china.org/topics/3287/laravel-53-uses-laravel-passport-to-build-the-back-end-authentication-api

Laravel在5.4中引入了新的官方OAuth扩展Laravel Passport,之前在5.1/5.2时一直是用dingo+jwt这一套来构建后端api,最近正好要构建新项目,想着试试官方这一个拓展如何。

安装#

官方文档中有完整的安装调用过程,使用composer:

composer require laravel/passport

像使用其他组件一样,我们需要在config/app/phpproviders数组中注册Passport:

Laravel\Passport\PassportServiceProvider::class,

然后我们需要执行migrate创建相关的客户端数据表和令牌数据表,和passport:install来生成一些加密秘钥等,这些在官方文档中都有详细介绍。

构建认证函数#

官方文档中针对如何简单使用做了初步介绍,下面我试着构造一个完整的客户端授权流程,首先创建ApiController

php artisen make:controller Apicontroller

ApiController中引入AuthenticatesUsers模块:

<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
class ApiController extends Controller{
    use  AuthenticatesUsers;
    public function __construct(){
        $this->middleware('api');
    }
}

我们的客户端需要通过密码授权的方式来认证,我们需要在ApiController中重写AuthenticatesUsers部分功能函数来实现整个完整的授权流程,在这里我们调用Passport提供的oauth/token接口:

//调用认证接口获取授权码
    protected function authenticateClient(Request $request)
    {
        $credentials = $this->credentials($request);

        $data = $request->all();

        $request->request->add([
            'grant_type' => $data['grant_type'],
            'client_id' => $data['client_id'],
            'client_secret' => $data['client_secret'],
            'username' => $credentials['username'],
            'password' => $credentials['password'],
            'scope' => ''
        ]);

        $proxy = Request::create(
            'oauth/token',
            'POST'
        );

        $response = \Route::dispatch($proxy);

        return $response;
    }

    //以下为重写部分
    protected function authenticated(Request $request)
    {
        return $this->authenticateClient($request);
    }

    protected function sendLoginResponse(Request $request)
    {
        $this->clearLoginAttempts($request);

        return $this->authenticated($request);
    }

    protected function sendFailedLoginResponse(Request $request)
    {
        $msg = $request['errors'];
        $code = $request['code'];
        return $this->failed($msg, $code);
    }
}

在这里我们会遇到一个问题,官方文档中没有提及,就是我们要如何使用自定的用户名进行授权,找寻源码,其实在Laravel\Passport\Bridge\UserRepository.phpgetUserEntityByUserCredentials()函数中会看到这段代码:

if (method_exists($model, 'findForPassport')) {
    $user = (new $model)->findForPassport($username);
} else {
    $user = (new $model)->where('email', $username)->first();
}

我们只需要在我们配置在config/auth.php的模型中添加这段代码就可以完成自定义授权用户名,该方法和社区中另一个帖子方法一样:

 public function findForPassport($username) {
    return $this->where('phone', $username)->first();
 }

这样一个授权流程基本完成,接下来创建一个Api/LoginController:

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\ApiController;
use Illuminate\Http\Request;use App\Models\User;                
\\User.php我移动到了Models目录use Validator;class LoginController extends ApiController{
    // 登录用户名标示为phone字段
    public function username()
    {
        return 'phone';
    }
    //登录接口,调用了ApiController中一些其他函数succeed\failed,上文未提及,用于接口格式化输出
    public function login(Request $request){
    $validator = Validator::make($request->all(), [
        'phone'    => 'required|exists:users',
        'password' => 'required|between:6,32',
        ]);

        if ($validator->fails()) {
        $request->request->add([
            'errors' => $validator->errors()->toArray(),
            'code' => 401,
            ]);                     
        return $this->sendFailedLoginResponse($request);
    }

    $credentials = $this->credentials($request);

    if ($this->guard('api')->attempt($credentials, $request->has('remember'))) {
        return $this->sendLoginResponse($request);
    }

    return $this->failed('login failed',401);
    }}

构建路由#

最后routes/api.php中加入我们需要的路由:

Route::group([
    'prefix'=>'/v1',
    'middleware' => ['api']], function () {
    Route::post('/user/login','Api\LoginController@login');
});

测试#

最后在postmen中调用接口:
image_1b2543doiq521a5c17lh1h3k14ve9.png-81.7kB

结果正确返回。


共有 6 条评论

  1. avatar

    chendimao

    你好,为什么我的laravel5.4 装了passport之后database文件夹下的migrations没有自动生成oauth数据迁移的表呢?

    1. avatar

      admin

      passport的迁移文件在./vendor/laravel/passport/database 的目录下,当运行php artisan migrate时会自动执行此目录下的迁移文件。

  2. avatar

    changphp

    我在 return $this-˃failed($msg, $code); 报错,没有找到failed方法,自动调用魔术方法了,请问这个是什么原因,我需要怎样更正?

    1. avatar

      admin

      很抱歉,没看到评论这么久才回复。这个failed方法是我自定义的一个全局返回响应函数,集成了laravel的 return response();而已,你可以自己添加修改成自己想要的。

Top