欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Laravel 开发 RESTful API 中篇

程序员文章站 2022-03-24 19:15:16
...

api_token 认证

Laravel 中实现 API 认证有多种方式,这里我们会使用一个非常简化的方式。

开始之前,首先添加 api_tokenusers 表:

php artisan make:migration --table=users adds_api_token_to_users_table

然后编写这个迁移文件:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddsApiTokenToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('member', function (Blueprint $table) {
            $table->string('api_token', 60)->unique()->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('member', function (Blueprint $table) {
            $table->dropColumn(['api_token']);
        });
    }
}

最后执行迁移命令作用于数据表:

php artisan migrate

创建注册接口

好吧,再次从开天辟地说起

创建 laravel 登录认证

php artisan make:auth

php artisan migrate

这两个命令会生成用户登录注册所需要的所有东西,然后在浏览器中访问 http://your-app.test/register 即可。

接着说我们的创建接口

我们使用 RegisterController 来根据注册请求返回正确的响应。尽管 Laravel 开箱提供了认证功能,但是我们还是需要对其进行调整以便返回我们想要的响应数据。该控制器使用 RegistersUsers 来实现注册,实现逻辑如下:

public function register(Request $request)
{
    $this->validator($request->all())->validate();

    $this->guard()->login($user);

    return $this->registered($request, $user)
                    ?: redirect($this->redirectPath());
}

我们只需要在 RegisterController 中实现 registered 方法即可。该方法接收 $request$user 参数:

protected function registered(Request $request, $user)
{
    $user->generateToken();

    return response()->json(['data' => $user->toArray()], 201);
}

最终 App\Http\Controllers\Auth\RegisterController 中的代码如下

<?php

namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */
    use RegistersUsers;
    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = '/';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|alpha_num|between:4,8|confirmed',
            'password_confirmation' => 'required|alpha_num|between:4,8'
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array $data
     * @return \App\User
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }

    public function register(Request $request)
    {

        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        return $this->registered($request, $user) ?: redirect($this->redirectPath());
    }

    protected function registered(Request $request, $user)
    {
        $user->generateToken();
        return response()->json(['data' => $user->toArray()], 201);
    }
}

routes/api.php 中注册路由如下:

Route::post('register', 'Auth\[email protected]');

在上面的示例代码中,我们调用了 User 模型上的生成令牌方法,该方法现在不存在,需要手动添加:

public function generateToken()
{
   $this->api_token = str_random(60);![微信图片_20181205185326.png][1]
   $this->save();

   return $this->api_token;
}

至此,注册接口编写完成,用户现在可以通过注册接口进行注册了,感谢 Laravel 开箱提供的认证字段验证功能,如果你需要调整验证规则的话可以到 RegisterController 中查看 validator 方法。

接下来我们可以在postman中测验一下。

ps:在测试中,一定不要忘记在headers中添加标红的字段。


注册说完了,我们来说说登录

和注册接口一样,可以编辑 LoginController 控制器来支持 API 认证。为此,我们需要在 LoginController 覆盖 AuthenticatesUsers trait 提供的 login 方法:

public function login(Request $request)
{
    $this->validateLogin($request);

    if ($this->attemptLogin($request)) {
        $user = $this->guard()->user();
        $user->generateToken();

        return response()->json([
            'data' => $user->toArray(),
        ]);
    }

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

然后在 routes/api.php 中注册登录路由:

Route::post('login', 'Auth\[email protected]');

接下来,我们用postman来测试下登录接口

哎呦,报错了,提示我们Request 没有找到

Class App\Http\Controllers\Auth\Request does not exist

解决办法是添加use Illuminate\Http\Request;

再次请求就可以得到我们想要的数据了

{
  "data": {
    "id": 6,
    "name": "老柴",
    "email": "[email protected]",
    "email_verified_at": null,
    "created_at": "2018-12-05 10:51:04",
    "updated_at": "2018-12-05 11:04:24",
    "api_token": "S0EJSrBM4LVuhq69o95NFRxSyEHHO9vGzeODItiCfyBYYkQ8e0FbduCqi1ov"
  }
}

后面就可以拿着这个 api_token 作为令牌来请求需要认证的资源了。使用我们现有的策略,请求认证资源时,如果没有 tokentoken 错误,用户将会接收到未认证响应(401)。


既然有登录,那肯定就要有退出,接下来我们就说说退出

为了形成完整闭环,下面我们来编写退出登录接口,实现思路是用户发起退出登录请求时,我们将其对应的 token 字段值从数据库移除。

首先,在 routes/api.php 中注册路由:

Route::post('logout', 'Auth\[email protected]');

然后在 Auth\LoginController.php 中编写 logout 方法:

public function logout(Request $request)
{
    $user = Auth::guard('api')->user();

    if ($user) {
        $user->api_token = null;
        $user->save();
    }

    return response()->json(['data' => 'User logged out.'], 200);
}

ps:不要忘记添加 use Auth; & use App\User;

使用该策略,一旦退出,用户的所有令牌都会失效,访问需要认证的接口都会拒绝访问(通过中间件实现),这需要和前端配合来避免用户在没有访问任何内容的权限下保持登录状态。


一个闭环已经形成,接下来我们要通过中间件来完善它,也就是说通过中间件实现限制访问

api_token 创建之后,我们就可以在路由文件中应用认证中间件了:

api_token 创建之后,我们就可以在路由文件中应用认证中间件了:

Route::middleware('auth:api')
    ->get('/user', function (Request $request) {
        return $request->user();
    });

我们可以使用 $request->user()Auth 门面访问当前用户:

Auth::guard('api')->user(); // 登录用户实例
Auth::guard('api')->check(); // 用户是否登录
Auth::guard('api')->id(); // 登录用户ID  

接下来,我们将之前定义的会员相关路由进行分组:

Route::group(['middleware'=>'auth:api'], function () {//prefix('v1')->
    Route::get('member', 'Api\[email protected]');
    Route::get('member/{member}', 'Api\[email protected]');
    Route::post('member', 'Api\[email protected]');
    Route::put('member/{member}', 'Api\[email protected]');
    Route::delete('member/{member}', 'Api\[email protected]');
});

这样就不需要为每个路由设置中间件,现在看来虽然节省不了多少时间,但随着应用体量的增长,这样做的好处是保持路由的DRY(Don't Repeat Yourself)

我们用 postman 再访问文章接口就需要认证了:

api_token 到此就结束了


相关标签: laravel