Jwt

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值