Laravel 6 api 认证

交流群 375462817
视频教程 https://space.bilibili.com/476513143

api 认证

原理

  1. 注册:用户注册成功后,随机生成长字符串作为 token,原生 token 返回给用户。哈希后的 token 存到数据库里。
  2. 登陆:用户使用账号密码登陆成功,随机生成长字符串作为 token,原生 token 返回给用户。哈希后的 token 存到数据库里。
  3. 认证:将用户传来的 token 进行哈希,然后取数据库中查找哈希后的 token ,找到了就认证成功,否则失败。

创建项目与配置

composer create-project --prefer-dist laravel/laravel laravel6
php artisan migrate
添加 api_token 字段,可空,唯一,默认 null。(可直接修改,也可以创建下面的代码片段然后迁移)
Schema::table('users', function ($table) {
    $table->string('api_token', 80)->after('password')
                        ->unique()
                        ->nullable()
                        ->default(null);
});

php artisan migrate

我们的例子还需要设置 email 可为空,因为我们以用户名作为认证的依据

设置模型可以操作 api_token 字段

# App\User.php
protected $fillable = [
    'name', 'email', 'password', 'api_token',
];

修改 api_token 这个名称

如果修改字段名称 api_token,请记得改配置文件 config/auth.php 中的 stroage_key

'api' => [
    'driver' => 'token',
    'provider' => 'users',
    'hash' => false,
    'storage_key' => 'api_token',
],

guard 设置为 api,hash 设置为 true

// config/auth.php

'defaults' => [
    'guard' => 'api',     // 默认 api 认证
    'passwords' => 'users',
],

'api' => [
    'driver' => 'token',
    'provider' => 'users',
    'hash' => true,       // 利用 SHA-256 算法哈希你的令牌
],

设置所有请求和响应都是 json 格式

php artisan make:request BaseRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class BaseRequest extends FormRequest
{
    public function wantsJson(){
        return true;
    }
    
    public function expectsJson(){
        return true;
    }
    
}

// index.php
$response = $kernel->handle(
    $request = \App\Http\Requests\BaseRequest::capture()
);

编写 api 认证代码

Route::post('/register', 'Auth\ApiController@register');
Route::post('/login', 'Auth\ApiController@login');
Route::post('/refresh', 'Auth\ApiController@refresh');
Route::post('/logout', 'Auth\ApiController@logout');

php artisan make:controller Auth\ApiController

<?php

// email 设置可为空
// request 和 response 都是 json 格式
// api_token 设置可插入数据库    
    
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

class ApiController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')->except('login', 'register');
    }

    protected function username()
    {
        return 'name';
    }

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

        $api_token = Str::random(80);
        $data = array_merge($request->all(), compact('api_token'));
        $this->create($data);

        return compact('api_token');
    }

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255', 'unique:users',],
//            'email' => ['required', 'string', 'email', 'max:255',],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    protected function create(array $data)
    {
        return User::forceCreate([
            'name' => $data['name'],
//            'email' => $data['email'],
            'password' => password_hash($data['password'], PASSWORD_DEFAULT),
            'api_token' => hash('sha256', $data['api_token']),
        ]);
    }

    public function logout()
    {
        auth()->user()->update(['api_token' => null]);

        return ['message' => '退出登录成功'];
    }

    public function login()
    {
        $user = User::where($this->username(), request($this->username()))
            ->firstOrFail();

        if (!password_verify(request('password'), $user->password)) {
            return response()->json(['error' => '抱歉,账号名或者密码错误!'],
                403);
        }

        $api_token = Str::random(80);
        $user->update(['api_token' => hash('sha256', $api_token)]);

        return compact('api_token');
    }

    public function refresh()
    {
        $api_token = Str::random(80);
        auth()->user()->update(['api_token' => hash('sha256', $api_token)]);

        return compact('api_token');
    }
}

保护路由

middleware('auth:api')

给 Request 传 token

$response = $client->request('GET', '/api/user?api_token='.$token);

$response = $client->request('POST', '/api/user', [
    'headers' => [
        'Accept' => 'application/json',
    ],
    'form_params' => [
        'api_token' => $token,
    ],
]);

$response = $client->request('POST', '/api/user', [
    'headers' => [
        'Authorization' => 'Bearer '.$token,
        'Accept' => 'application/json',
    ],
]);