Laravel-JWT

JWT简介

JWT(JSON Web Token)实际上是一个字符串,包括头部、载荷、签名

载荷

{
    "sub": "1",
    "iss": "http://localhost:8000/auth/login",
    "iat": 1451888119,
    "exp": 1454516119,
    "nbf": 1451888119,
    "jti": "37c107e4609ddbcc9c096ea5ee76c667"
}

这6个字段是由JWT标准所定义的

  • sub:该JWT所面向的对象
  • iss:该JWT的签发者
  • iat(issued at):在什么时候签发的token
  • exp(expires):token什么时候过期
  • nbf(not before):token在此时间之前不能被接收处理
  • jti:JWT ID为web token提供唯一标识

将上面的JSON对象进行base64编码后得到的字符串就是JWT的载荷

yJzdWIiOiIxIiwiaXNzIjoiaHR0cDpcL1wvbG9jYWx
ob3N0OjgwMDFcL2F1dGhcL2xvZ2luIiwiaWF0IjoxNDUxODg4MTE5LCJleHAiOjE0NTQ1MTYxMTksIm5iZiI6MTQ1MTg4OD
ExOSwianRpIjoiMzdjMTA3ZTQ2MDlkZGJjYzljMDk2ZWE1ZWU3NmM2NjcifQ

头部

WT还需要一个头部,头部用于描述关于该JWT的最基本的信息

{
  //表明其类型和签名算法
  "typ": "JWT",
  "alg": "HS256"
}

对其进行Base64编码后就得到JWT的头部(Header)

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

签名

将头部和荷载编码后的字符串用.连接在一起(头部在前):

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaXNzIjoiaHR0cDpcL1wvbG9jYWx
ob3N0OjgwMDFcL2F1dGhcL2xvZ2luIiwiaWF0IjoxNDUxODg4MTE5LCJleHAiOjE0NTQ1MTYxMTksIm5iZiI6MTQ1MTg4OD
ExOSwianRpIjoiMzdjMTA3ZTQ2MDlkZGJjYzljMDk2ZWE1ZWU3NmM2NjcifQ

将上面拼接完的字符串用HS256算法进行加密,同时提供一个密匙(secret):

HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)

加密后的到的字符串称为签名:

wyoQ95RjAyQ2FF3aj8EvCSaUmeP0KUqcCJDENNfnaT4

将这一部分拼接在被签名的字符串后面就形成了JWT

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaXNzIjoiaHR0cDpcL1wvbG9jYWx
ob3N0OjgwMDFcL2F1dGhcL2xvZ2luIiwiaWF0IjoxNDUxODg4MTE5LCJleHAiOjE0NTQ1MTYxMTksIm5iZiI6MTQ1MTg4OD
ExOSwianRpIjoiMzdjMTA3ZTQ2MDlkZGJjYzljMDk2ZWE1ZWU3NmM2NjcifQ.wyoQ95RjAyQ2FF3aj8EvCSaUmeP0KUqcCJDENNfnaT4

Laravel使用JWT

使用composer安装

composer require tymon/jwt-auth 1.0.0-rc.3
指定版本号,可以根据官网,不指定在生成配置文件时无法生成(坑)

这条命令会在config下增加一个jwt.php配置文件

php artisan vendor:publish –provider=”Tymon\JWTAuth\Providers\LaravelServiceProvider”

生成加密密钥(注意在服务器端拉去代码后要执行这一句话)

php artisan jwt:secret

config/jwt.php中可以配置的选项:

  • ttl:token有效期(分钟)
  • refresh_ttl:刷新token时间(分钟)
  • algo:token签名算法
  • user:指向User模型的命名空间路径
  • identifier:用于从token的sub中获取用户
  • require_claims:必须出现在token的payload中的选项,否则会抛出- TokenInvalidException异常
  • blacklist_enabled:如果该选项被设置为false,那么我们将不能废止token,即使我们刷新了token,前一个token仍然有效
  • providers:完成各种任务的具体实现,如果需要的话你可以重写他们
    • User —— providers.user:基于sub获取用户的实现
    • JWT —— providers.jwt:加密/解密token
    • Authentication —— providers.auth:通过证书/ID获取认证用户
    • Storage —— providers.storage:存储token直到它们失效

模型使用

如果使用User表生成token,需要增加一些代码

<?php
namespace App;

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

class User extends Authenticatable implements JWTSubject    # 这里别忘了加
{
    use Notifiable;

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }
}
>

配置文件修改

注册两个Facade

config/app.php

'aliases' => [
    //添加以下两行
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
    'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
]

也可以不注册使用这两个Facede,而使用auth()函数

修改auth.php

config/auth.php

'guards' => [
    'web' => [
        'driver' => 'session',//改不改视具体情况而定
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'jwt',      // 原来是 token 改成 jwt
        'provider' => 'users',
    ],
],

注册路由

Route::group([
    'middleware' => 'api',
    'prefix' => 'auth'
],function ($router){
    Route::post('login','AuthController@login');
    Route::post('logout','AuthController@logout');
    Route::post('refresh','AuthController@refresh');
    Route::post('me','AuthController@me');
});

创建控制器

php artisan make:controller AuthController

AuthController内容

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;//自定义验证字段时要引入请求
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api',['except'=> ['login']]);
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $credentials = [
            'username' => $request->input('username'),
            'password' => $request->input('password')
        ];

        //标记用户登录成功
        if (! $token = auth('api')->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(auth('api')->user());
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();

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

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(auth('api')->refresh());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60
        ]);
    }
}