Laravel 中使用 JWT(Json Web Token) 实现基于API的用户认证

2021年的第一篇文章;
JWT(JSON Web Token)是一个非常轻巧的规范;
这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
一个JWT实际上就是一个字符串;
我们可以通过这个字符串;
转化为用户信息;

写这篇文章的原因:
网上存在很多JWT的文章;
但是一般都是讲JWT算法与加密方式之类的;
云里雾里的;

集成JWT到Laravel项目里面;
我们使用Composer安装jwt扩展包:

composer require tymon/jwt-auth

注:如果你是用的 tymon/jwt-auth 是 0.5.* 版本的,请使用php artisan jwt:generate命令生成密钥。

注册需要用到的对应门面:
放在app.php 文件里面;

'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class

下一步发布对应的配置文件;

php artisan vendor:publish --provider='Tymon\JWTAuth\Providers\JWTAuthServiceProvider'

最后生成密钥;

php artisan jwt:secret

接下来在用户的对应模型里面添加下面代码;

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    /**
     * @var string 表名
     */
    public $table = 'member';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

添加完成之后;
开始创建token;

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
use App\User;
use Tymon\JWTAuth\Facades\JWTAuth;

Route::get('/', function (){

    // 创建token
    $user  = User::find(7);
    $token = JWTAuth::fromUser($user);
    dd($token);

//    return view('welcome');
});

看看请求的的结果;

生成token

然后这个就是根据用户生成的token;
再把这个生成的token放在请求里面;
注意这里规定就是这种格式;
等下我们会说到为什么是这种格式;

Authorization : Bearer {your token}

我们在根据请求头里面的token转化成用户信息;

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
use App\User;
use Tymon\JWTAuth\Facades\JWTAuth;

Route::get('/', function (){

    // 获取用户信息
    $user = JWTAuth::parseToken()->authenticate();

    dd($user);

//    return view('welcome');
});

根据token获取用户信息

哈哈哈;
token成功转化为用户信息;
以上是生成token , 然后将token转化为用户信息;

下面是通过登录实现用户认证;
如果登录成功则返回相应用户的token;

use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

class AuthenticateController extends Controller
{
    public function authenticate(Request $request)
    {
        // 获取登录用到的邮箱与密码参数
        $credentials = $request->only('email', 'password');
        try {
            // 校验邮箱与密码是否成功
            if (! $token = JWTAuth::attempt($credentials)) {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        } catch (JWTException $e) {
            // 创建token失败
            return response()->json(['error' => 'could_not_create_token'], 500);
        }
        // 返回token信息
        return response()->json(compact('token'));
    }
}

tymon/jwt-auth 扩展还提供了两个中间件;
GetUserFromToken和RefreshToken;
前者用于在请求头和参数中检查是否包含token,并尝试对其解码;
后者会再次从请求中解析token;
并顺序刷新token(同时废弃老的token)并将其作为下一个响应的一部分;
要使用这两个中间件;
需要到app/Http/Kernel.php下的$routeMiddleware属性中注册它们:

  /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        // 
        'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
        'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
    ];

最后我们来讲一下我们的请求头里面为什么是如下格式的:

Authorization : Bearer {your token}

我们来看一下源代码;
进入到 vendor\tymon\jwt-auth\src\Http\Parser\AuthHeaders.php 这个文件里面;

namespace Tymon\JWTAuth\Http\Parser;

use Illuminate\Http\Request;
use Tymon\JWTAuth\Contracts\Http\Parser as ParserContract;

class AuthHeaders implements ParserContract
{
    /**
     * The header name.
     *
     * @var string
     */
    protected $header = 'authorization';

    /**
     * The header prefix.
     *
     * @var string
     */
    protected $prefix = 'bearer';

    /**
     * Attempt to parse the token from some other possible headers.
     *
     * @param  \Illuminate\Http\Request  $request
     *
     * @return null|string
     */
    protected function fromAltHeaders(Request $request)
    {
        return $request->server->get('HTTP_AUTHORIZATION') ?: $request->server->get('REDIRECT_HTTP_AUTHORIZATION');
    }

    /**
     * Try to parse the token from the request header.
     *
     * @param  \Illuminate\Http\Request  $request
     *
     * @return null|string
     */
    public function parse(Request $request)
    {
        $header = $request->headers->get($this->header) ?: $this->fromAltHeaders($request);

        if ($header && preg_match('/'.$this->prefix.'\s*(\S+)\b/i', $header, $matches)) {

            // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sYXJhdmVsNS41LmNvbSIsImlhdCI6MTYxNDY3ODYwOSwiZXhwIjoxNjE0NjgyMjA5LCJuYmYiOjE2MTQ2Nzg2MDksImp0aSI6InBqNkxMOEowVTR3V0JJSXUiLCJzdWIiOjcsInBydiI6Ijg3ZTBhZjFlZjlmZDE1ODEyZmRlYzk3MTUzYTE0ZTBiMDQ3NTQ2YWEifQ.iTEbTl9eRCv9U500QcoGcGFlMqUjhqEhnwIO4NcZQWE
            return $matches[1];
        }
    }

哈哈哈;
饭后小甜点;
学无止境;

史大坨博客
请先登录后发表评论
  • 最新评论
  • 总共0条评论