signature=406355c796db59b5424a3861d01f0f1d,Laravel JWT完整使用图文教程

JWT全称JSON Web Tokens,是一个非常轻巧的规范。这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。它的两大使用场景是:认证和数据交换。

第一步、下载composer

# 建议使用1.0以上版本

composer require tymon/jwt-auth 1.*@rc

1558627931218378.png

第二步、生成文件、修改配置

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider

1559116735279140.png

php artisan jwt:secret

1559116756457314.png[root@localhost laravel_base]# php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

Copied File [/vendor/tymon/jwt-auth/config/config.php] To [/config/jwt.php]

Publishing complete.

[root@localhost laravel_base]# php artisan jwt:secret

jwt-auth secret [Jyxc5QkfSSEHNv7XC6wW4YDw0HvBAoApPYfGhnyv5bhylmhyGSw8U44r1FKonviY] set successfully.

1558627946222944.png

2.1 发布配置文件

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

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

2.2 生成加密密钥

# 这条命令会在 .env 文件下生成一个加密密钥,如:JWT_SECRET=foobar

php artisan jwt:secret[root@localhost laravel_base]# php artisan jwt:secret

This will invalidate all existing tokens. Are you sure you want to override the secret key? (yes/no) [no]:

> yes

jwt-auth secret [4Zule0z1Fy1BMPbW6MvCmFLhZV9ym9QaWlRqCft1BbMkvjLpmYWQ4akLi7hFSHE3] set successfully.

2.3 更新模型

如果你使用默认的 User 表来生成 token,你需要在该模型下增加一段代码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;

// Rest omitted for brevity

/**

* 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 [];

}}

2.4 注册两个 Facade

这两个 Facade 并不是必须的,但是使用它们会给你的代码编写带来一点便利。

config/app.php'aliases' => [

...

// 添加以下两行

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

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

],

1558629292797438.png

如果你不使用这两个 Facade,你可以使用辅助函数 auth ()

auth () 是一个辅助函数,返回一个 guard,暂时可以看成 Auth Facade。// 如果你不用 Facade,你可以这么写

auth('api')->refresh();

// 用 JWTAuth Facade

JWTAuth::parseToken()->refresh();

如果你不使用这两个 Facade,你可以使用辅助函数 auth ()

auth () 是一个辅助函数,返回一个 guard,暂时可以看成 Auth Facade。

2.5 修改 auth.php

config/auth.php

'guards' => [

'web' => [

'driver' => 'session',

'provider' => 'users',

],

'api' => [

'driver' => 'jwt',      // 原来是 token 改成jwt

'provider' => 'users',

],

],

'providers' => [

'users' => [

'driver' => 'eloquent',

'model' => App\User::class, //如果你的providers 不是这个User class类,那么需要指定到你的class 文件Z:\laravel_base\config\auth.php

],

// 'users' => [

//     'driver' => 'database',

//     'table' => 'users',

// ],

],

1559173954742352.png

2.6 注册一些路由

注意:在 Laravel 下,route/api.php 中的路由默认都有前缀 api 。Route::group([

'prefix' => 'auth'

], function ($router) {

Route::post('login', 'AuthController@login');

Route::post('logout', 'AuthController@logout');

Route::post('refresh', 'AuthController@refresh');

Route::post('me', 'AuthController@me');

});

2.7 新建控制器类<?php

namespace App\Http\Controllers;

use App\User;

use Illuminate\Support\Facades\Auth;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\DB;

use Tymon\JWTAuth\JWT;

use Tymon\JWTAuth\JWTAuth;

class AuthController extends Controller {

/**

* Create a new AuthController instance.

* 要求附带email和password(数据来源users表)

*

* @return void

*/

public function __construct() {

// 这里额外注意了:官方文档样例中只除外了『login』

// 这样的结果是,token 只能在有效期以内进行刷新,过期无法刷新

// 如果把 refresh 也放进去,token 即使过期但仍在刷新期以内也可刷新

// 不过刷新一次作废

$this->middleware('jwt.auth', ['except' => ['login']]);

// 另外关于上面的中间件,官方文档写的是『auth:api』

// 但是我推荐用 『jwt.auth』,效果是一样的,但是有更加丰富的报错信息返回

}

/**

* Get a JWT via given credentials.

*

* @return \Illuminate\Http\JsonResponse

*/

public function login() {

//$data=User::active()->get();

//

//return $data;

//

//print_r(request()->input('access_token'));

//

//exit;

$credentials = request(['email', 'password']);

//$credentials = request(['name', '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('api')->logout();

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

}

/**

* Refresh a token.

* 刷新token,如果开启黑名单,以前的token便会失效。

* 值得注意的是用上面的getToken再获取一次Token并不算做刷新,两次获得的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

]);

}

}

这里面只有一个login是不验证的,其他方法都是验证token的,

1559174215180479.png

另外注意一点,且必须包含一个password字段,这是不能丢弃的,否则jwt插件用不了password

我们明文传递上来,保存在数据库中的字段是\Hash::make('123456');

加密的一个字符串

有了以上的配置几点,看一下运行结果:

看实际调用

login登录

1559174439448695.png

access_token 成功了

token的类型是 bearer

获取用户

auth/me

1559174606144019.png

要访问auth/me必须传递token 串,传递方式 header 头的形式

Authorization   名字

bearer 这是类型,token字符串eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjMxLjEyODo4OTAxXC9hcGlcL2F1dGhcL2xvZ2luIiwiaWF0IjoxNTU5MTc0NDg1LCJleHAiOjE1NTkxNzgwODUsIm5iZiI6MTU1OTE3NDQ4NSwianRpIjoidU9KT3ZMaVBCWkRhYkk2dyIsInN1YiI6MSwicHJ2IjoiODdlMGFmMWVmOWZkMTU4MTJmZGVjOTcxNTNhMTRlMGIwNDc1NDZhYSJ9.ImxOqXPB6J8L-j8x0VqIuLnOcOxpjOJ1d4Tx_i2mAOg

如果字符串传递错误,就会返回

Unauthorized

401           

Unauthorized           

auth("api") 会返回Tymon\JWTAuth\JWTGuard

这样的一个类,里面有具体的方式和方法

具体就到这里。

官方手册:

其他知识普及:

token的创建 不止一种,接下来介绍token的三种创建方法:

1、基于账号和密码参数

2、基于user模型返回的实例

3、基于users模型中的用户主键id

1)基于账号和密码参数// 使用辅助函数

$credentials = request(['email', 'password']);

$token = auth()->attempt($credentials)

// 使用 Facade

$credentials = $request->only('email', 'password');

$token = JWTAuth::attempt($credentials);

2)基于user模型返回的实例// 使用辅助函数

$user = User::where('username','=','admin')->where('password','=','password123')->first();

$token = auth()->login($user);

// 使用 Facade

$user = User::first();

$token = JWTAuth::fromUser($user);

3)基于users模型中的用户主键id

2.3 token 的解析

a) 解析 token 到对象

只有 Facade 需要这样。

// 把请求发送过来的直接解析到对象

JWTAuth::parseToken();

b) 获取 token 中的 user 信息

// 辅助函数

$user = auth()->user();

// Facade

$user = JWTAuth::parseToken()->authenticate();

c) 获取 token

如果 token 被设置则会返回,否则会尝试使用方法从请求中解析 token ,如果token未被设置或不能解析最终返回false。

// 辅助函数

$token = auth()->getToken();

// Facade

$token = JWTAuth::parseToken()->getToken();

更多方法可以看文章后面的附录。

d) 如果是前端

直接 base64 解码 token 的前两段即可以知道所需的信息。

头部(header)

头部通常由两部分组成:令牌的类型(即JWT)和正在使用的散列算法(如HMAC SHA256 或 RSA.)。

例如:{

"alg": "HS256",

"typ": "JWT"

}

然后用 Base64Url 编码得到头部,即 xxxxx。

载荷(Payload)

载荷中放置了 token 的一些基本信息,以帮助接受它的服务器来理解这个 token,载荷的属性也分三类:预定义(Registered)、公有(public)和私有(private),接下来主要介绍预定义的。{

"sub": "1",

"iss": "http://localhost:8000/auth/login",

"iat": 1451888119,

"exp": 1454516119,

"nbf": 1451888119,

"jti": "37c107e4609ddbcc9c096ea5ee76c667"

}

这里面的前6个字段都是由JWT的标准所定义的,也就是预定义(Registered claims)的。

sub: 该JWT所面向的用户

iss: 该JWT的签发者

iat(issued at): 在什么时候签发的token

exp(expires): token什么时候过期

nbf(not before):token在此时间之前不能被接收处理

jti:JWT ID为web token提供唯一标识

将上面的 json 进行 Base64Url 编码得到载荷,,即 yyyyy。

签名(Signature)

签名时需要用到前面编码过的两个字符串,如果以 HMACSHA256 加密,就如下:HMACSHA256(

base64UrlEncode(header) + "." +

base64UrlEncode(payload),

secret

)

加密后再进行 base64url 编码最后得到的字符串就是 token 的第三部分 zzzzz。

组合便可以得到 token:xxxxx.yyyyy.zzzzz。

a) 载荷设置

载荷信息会在 token 解码时得到,同时越大的数组会生成越长的 token ,所以不建议放太多的数据。同时因为载荷是用 Base64Url 编码,所以相当于明文,因此绝对不能放密码等敏感信息。$customClaims = ['foo' => 'bar', 'baz' => 'bob'];

// 辅助函数

$token = auth()->claims($customClaims)->attempt($credentials);

// Facade - 1

$token = JWTAuth::claims($customClaims)->attempt($credentials);

b) 载荷解析

从请求中把载荷解析出来。可以去看扩展源代码,里面还有很多的方法。

// 辅助函数$exp = auth()->payload()->get('exp');

$json = auth()->payload()->toJson();

$array = auth()->payload()->jsonSerialize();

$sub = $array['sub'];

// Facade - 1

$payload = JWTAuth::parseToken()->getPayload();

$payload->get('sub'); // = 123

$payload['jti']; // = 'asfe4fq434asdf'

$payload('exp') // = 123456

$payload->toArray(); // = ['sub' => 123, 'exp' => 123456, 'jti' => 'asfe4fq434asdf'] etc

// Facade - 2

$exp = JWTAuth::parseToken()->getClaim('exp');

4. token 的三个时间

一个 token 一般来说有三个时间属性,其配置都在 config/jwt.php 内。

有效时间

有效时间指的的是你获得 token 后,在多少时间内可以凭这个 token 去获取内容,逾时无效。

// 单位:分钟

'ttl' => env('JWT_TTL', 60)

刷新时间

刷新时间指的是在这个时间内可以凭旧 token 换取一个新 token。例如 token 有效时间为 60 分钟,刷新时间为 20160 分钟,在 60 分钟内可以通过这个 token 获取新 token,但是超过 60 分钟是不可以的,然后你可以一直循环获取,直到总时间超过 20160 分钟,不能再获取。

// 单位:分钟

'refresh_ttl' => env('JWT_REFRESH_TTL', 20160)

宽限时间

宽限时间是为了解决并发请求的问题,假如宽限时间为 0s ,那么在新旧 token 交接的时候,并发请求就会出错,所以需要设定一个宽限时间,在宽限时间内,旧 token 仍然能够正常使用。

// 宽限时间需要开启黑名单(默认是开启的),黑名单保证过期token不可再用,最好打开

'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true)

// 设定宽限时间,单位:秒

'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 60)

JWT 完整使用详解

这是一个完整版的jwt非常详细 ,推荐查看:

其他逻辑,https://learnku.com/articles/6216/laravel-uses-jwt-to-implement-api-auth-to-build-user-authorization-interfaces

https://laravelacademy.org/post/3640.html

参考文章:

https://learnku.com/articles/10885/full-use-of-jwt

https://blog.csdn.net/qq_36514588/article/details/82186617

https://learnku.com/articles/10889/detailed-implementation-of-jwt-extensions

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值