jwt学习
【学习目标】
- 掌握JWT概念
- 了解JWT优缺点
- 了解JWT使用场景
- 掌握JWT验证机制
- 掌握JWT使用
1.1 为什么使用鉴权认证?
案例1 学生进出学校大门
案例2 男生追女生
防止信息被篡改和伪造
最终为了保证数据在通信时的安全性
1.2 JWT是什么?
JWT是JSON Web Tokens的简称,从单词可以看出它也是一种token,其实可以理解为一种生成token的框架或规范,是目前最流行的跨域认证解决方案之一。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjNmMmc1N2E5MmFhIn0.eyJpYXQiOjE1NjI4MzM0MDgsImlzcyI6Imh0dHA6XC9cL3d3dy5weWcuY29tIiwiYXVkIjoiaHR0cDpcL1wvd3d3LnB5Zy5jb20iLCJuYmYiOjE1NjI4MzM0MDcsImV4cCI6MTU2MjkxOTgwOCwianRpIjoiM2YyZzU3YTkyYWEiLCJ1c2VyX2lkIjoxfQ.NFq1qQ-Z5c4pwit8ZkyWEwX6SBXmnHJcc6ZDgSD5nhU
Header(头部):描述 JWT 的元数据
{
“alg”: “HS256”,
“typ”: “JWT”
}
Payload(负载):用来存放实际需要传递的数据
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
名称 | 说明 | 解释 |
---|---|---|
iss (issuer) | 签发人 | issuer 请求实体,可以是发起请求的用户的信息,也可是jwt的签发者 |
sub (Subject) | 主题 | 设置主题,类似于发邮件时的主题 |
aud (audience) | 受众 | 接收jwt的一方,接收人 |
exp (expire) | 过期时间 | token过期时间,时间戳 |
nbf (not before) | 生效时间 | 当前时间在nbf设定时间之前,该token无法使用 |
iat (issued at) | 签发时间 | token创建时间 |
jti (JWT ID) | 编号 | 对当前token设置唯一标示 |
除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。
{ "sub": "除了帅一无所有", "name": "张三", "status": "1" }
Signature(签名):对前两部分的签名,防止数据篡改
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
保证数据访问安全
案例1 学生进出学校大门
案例2
1.3 为什么使用JWT?
1.效率高,方便扩展
2.避免CSRF风险
3.适合APP前后端分离场景
1.4 JWT缺点
1.一旦签发不能撤销
2.不能自动续签
1.5 JWT使用场景
1.一次性验证
2.RESTful接口安全认证
1.6 JWT验证机制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yFcNMaoP-1620959349259)(/Users/songxinfu/Desktop/WechatIMG8.jpeg)]
1.7 如何使用JWT
1.7.1 jwt组件安装
composer require lcobucci/jwt 3.3
1.7.2 JWT封装
namespace tools\jwt;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;
/**
* token封装
*/
class Token
{
private static $_config = [
'audience' => 'http://www.abc.com',//接收人
'id' => '3f2g57a92aa',//token的唯一标识,这里只是一个简单示例
'sign' => 'abc',//签名密钥
'issuer' => 'http://api.abc.com',//签发人
'expire' => 3600*24 //有效期
];
//生成token
public static function getToken($user_id){
//签名对象
$signer = new Sha256();
//获取当前时间戳
$time = time();
//设置签发人、接收人、唯一标识、签发时间、立即生效、过期时间、用户id、签名
$token = (new Builder())->issuedBy(self::$_config['issuer'])
->canOnlyBeUsedBy(self::$_config['audience'])
->identifiedBy(self::$_config['id'], true)
->issuedAt($time)
->canOnlyBeUsedAfter($time-1)
->expiresAt($time + self::$_config['expire'])
->with('user_id', $user_id)
->sign($signer, self::$_config['sign'])
->getToken();
return (string)$token;
}
//从请求信息中获取token令牌
public static function getRequestToken()
{
if (empty($_SERVER['HTTP_AUTHORIZATION'])) {
return false;
}
$header = $_SERVER['HTTP_AUTHORIZATION'];
$method = 'bearer';
//去除token中可能存在的bearer标识
return trim(str_ireplace($method, '', $header));
}
//从token中获取用户id (包含token的校验)
public static function getUserId($token = null)
{
$user_id = null;
$token = empty($token)?self::getRequestToken():$token;
if (!empty($token)) {
//为了注销token 加以下if判断代码
$delete_token = cache('delete_token') ?: [];
if(in_array($token, $delete_token)){
//token已被删除(注销)
return $user_id;
}
$token = (new Parser())->parse((string) $token);
//验证token
$data = new ValidationData();
$data->setIssuer(self::$_config['issuer']);//验证的签发人
$data->setAudience(self::$_config['audience']);//验证的接收人
$data->setId(self::$_config['id']);//验证token标识
if (!$token->validate($data)) {
//token验证失败
return $user_id;
}
//验证签名
$signer = new Sha256();
if (!$token->verify($signer, self::$_config['sign'])) {
//签名验证失败
return $user_id;
}
//从token中获取用户id
$user_id = $token->getClaim('user_id');
}
return $user_id;
}
}
1.7.3 JWT使用
1.token生成
$result = $this->validate(input(), 'Jwt');
if (true !== $result) {
return json(["code" => "failed", "message" => $result]);
}
$adminInfo = \app\mobile\model\Jwt::where('username', input("username"))->find();
$password = md5(input("password"));
if ($adminInfo["password"] != $password) {
$apiRes = ['code' => "failed", "message" => '登录失败'];
return json($apiRes);
}
$adminId = $adminInfo["id"];
$token = \tools\jwt\Token::getToken($adminId);
$apiRes = ['code' => "success", "message" => "token获取成功", "data" => ["token" => $token]];
return json($apiRes);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V6Srw52g-1620959349261)(/Users/songxinfu/Desktop/2A740F38-9875-4990-9756-989F1A7E724F.png)]
2.前端传token参数
header头
post 提交
3.jwt token验证
$token = input("token");
if(!$token) {
$apiRes = ['code' => "failed", "message" => "token不能为空"];
return json($apiRes);
}
$userid = \tools\jwt\Token::getUserId($token);
if (empty($userid)) {
$apiRes = ['code' => "failed", "message" => "鉴权失败"];
} else {
$apiRes = ['code' => "success", "message" => "鉴权成功"];
}
return json($apiRes);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMt79UQ0-1620959349263)(/Users/songxinfu/Desktop/748C3372-B5C5-4456-B8E8-98232453F437.png)]
1.8 总结
知识回顾
JWT概念和结构(互动)
JWT 用途(互动)
JWT怎么使用
s