Laravel5.6 使用 JWT 开发API中的疑惑

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37035946/article/details/87862117

使用JWT参考文章:JWT的使用JWT使用完整详解

简单梳理几个疑惑点。记录一下。

首先要区分laravel自带的auth认证方法和jwt的认证方法有哪些,别搞混了,你用jwt的方式生成token,用自带的auth去验证这就不对了。

安装完JWT可用中间件有:auth、auth:api、jwt.auth、jwt.refresh、jwt.check、jwt.renew

1、在传统的做法中, 服务器会保存生成的token, 当客户端发送来token时, 与服务器的进行比对, 但是 jwt 的不需要在服务器保存任何 token, 而是使用一套加密/解密算法 和 一个密钥 来对用户发来的token进行解密, 解密成功后就可以得到这个用户的信息,JWT的token无需主动销毁。

2、JWT 的使用有两种方式:

1、加到 url 中:?token=你的token
2、加到 header 中,建议用这种,因为在 https 情况下更安全:Authorization:Bearer 你的token

 3、JWT 在客户端的存储有三种方式:

1、LocalStorage
2、SessionStorage
3、Cookie [不能设置 HTTPonly]
但是最推荐的还是第三种,因为第一二种存在跨域读取限制,而 Cookie 使用不同的跨域策略

 4、中间件之区别

jwt.refresh 和 jwt.auth

这个的区别就是前者会在响应的 header 头中增加刷新的新 token。

jwt.auth 和 auth:api(auth)

这两个功能完全一致,只是调用链有所差别,而这个差别正好可以体现上面提到的低耦合性

因此

$this->middleware('auth:api', ['except' => ['login']]);
等同于
$this->middleware('jwt.auth', ['except' => ['login']]);

 5、辅助函数 auth()

auth 函数返回一个 认证 实例。为了方便起见,你可以使用它来替代 Auth Facade:

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

如果需要,你可以指定你想要访问的认证实例:

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

6、Facade     config/app.php

'aliases' => [
    ...
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
    'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],

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

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

auth() 是一个辅助函数,返回一个guard,如果不指定guard,就是用auth.php文件里的default的guard,laravel是web,Lumen是api。

7、 Token的创建

  • 基于账密参数
  • 基于 users 模型返回的实例
  • 基于 users 模型中的用户主键 id
a) 基于账密参数
// 使用辅助函数
$credentials = request(['email', 'password']); 
$token = auth()->attempt($credentials)

// 使用 Facade
$credentials = $request->only('email', 'password');
$token = JWTAuth::attempt($credentials);
b) 基于 users 模型返回的实例
// 使用辅助函数
$user = User::first();
$token = auth()->login($user);

// 使用 Facade
$user = User::first();
$token = JWTAuth::fromUser($credentials);

c) 基于 users 模型中的主键 id
// 使用辅助函数
$token = auth()->tokenById(1);

// 使用 Facade
源码中没找到

8、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 的前两段即可以知道所需的信息。

9、 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)

10、 token 的刷新问题

a) token 为什么要刷新吗?
首先 Basic Auth 是一种最简单的认证方法,但是由于每次请求都带用户名和密码,频繁的传输肯定不安全,所以才有 cookies 和 session 的运用。如果 token 不刷新,那么 token 就相当于上面的用户名+密码,只要获取到了,就可以一直盗用,因此 token 设置有效期并能够进行刷新是必要的。
b) token 有效期多久合适,刷新频率多久合适?
有效期越长,风险性越高,有效性越短,刷新频率越高,刷新就会存在刷新开销,所以这需要综合考虑。而且 web 端应该设置为分钟级和小时级,而移动端应该设置为天级和周级。
c) 有没有必要每次都刷新 token ?
根据业务需求,方便的同时也会给内存造成不小的压力,用户访问量不打可以写个中间件,每次请求都刷新token。

 11、附录

1. JWT 的 两个 Facade
JWTAuth
JWTAuth::parseToken()->方法() 一般都可以换成 auth()->方法()。

token 生成
attempt
根据 user 账密新建一个 token。
$credentials = $request->only('email', 'password');
$token = JWTAuth::attempt($credentials);

romUser or fromSubject
根据 user 对象生成一个 token。后者是前者别名。
$user = User::find(1);
$token = JWTAuth::fromUser($user);

token 控制
refresh
更新 token。
$newToken = JWTAuth::parseToken()->refresh();

invalidate
让一个 token 无效。
JWTAuth::parseToken()->invalidate();

check
检验 token 的有效性。
if(JWTAuth::parseToken()->check()) {
    dd("token是有效的");
}

12、token解析

authenticate or toUser or user
这三个效果是一样的,toUser 是 authenticate 的别名,而 user 比前两者少一个 user id 的校验,但并没有什么影响。
e$user = JWTAuth::parseToken()->toUser();r
);
parseToken
从 request 中解析 token 到对象中,以便进行下一步操作。
JWTAuth::parseToken();

getToken
从 request 中获取token
$token = JWTAuth::getToken();  // 这个不用 parseToken ,因为方法内部会自动执行一次

其他一些用法
这里用 auth 的写法,因为 Laravel 有多个 guard,默认 guard 也不是 api ,所以需要写成 auth('api') 否则,auth() 即可

重写有效时间
$token = auth('api')->setTTL(7200)->attempt($credentials);

验证账密是否正确
$boolean = auth('api')->validate($credentials);

auth('api')->user()->only(['name'])

13、Token验证是否登录

Auth::check() 是判断用户是否登录的方法,如果使用的默认用户系统,那这样使用没问题。(即default默认配置的guard)

但是使用两组用户的话,如何使用各组用户的功能呢? Auth::guard('users')->check() 就是用来判断前台用户是否登录,而 Auth::guard('admins')->check() 就是用来判断后台用户是否登录的。一般来说,你的 auth.php 配置文件中,会配置一个default用户组,一般为users,则使用users组用户时候不用指定guard,而使用其他组用户时候,则需要使用guard来指定使用的哪组用户

猜你喜欢

转载自blog.csdn.net/qq_37035946/article/details/87862117