JWT详细解读

一.什么是JWT?

jwt 全称是 json web token ,我自己用自认为很通俗的话来解释一下:

  • json 是指 json 格式的数据。
  • web 大家都知道是什么,通俗来说就是大家浏览的网站。
  • token 翻译过来就是令牌。

连起来就是:json 格式的数据编码加密到达一个 token 字符串,然后这个字符串可以用来做 web 应用的认证。

二.使用JWT。

1.JWT的组成。

jwt 规定由三部分组成,分别是 headerpayloadsignature,下面我们来看看这但部分分别是什么:

  • header 头部。
  • type 类型说明,基本上是 jwt
  • alg 用于加密的 hash 算法。
    {
       "type":"jwt",
       "alg":"HS256"
   }
  • payload 载荷。
  • iss : jwt 的签发者。
  • sub : jwt 所面向的用户。
  • sud : 接受 jwt 的一方。
  • exp : jwt 的过期时间。
  • nbf : 定义在什么时间之前,该 jwt 都是不可用的。
  • iat : jwt 的签发时间。
  • jti : jwt 的唯一身份标识,主要用来作为一次性 token,而避免重放攻击。

以上的 payload 建议但是不强制使用,特别注意,因为 payload 可以被解码,所以不能存放一些,敏感的数据。

  • sianature 签名,该签名是一个字符串,这个字符串的生成方法如下:
  • 通过”base64URL“安全编码后的header。
  • 通过”base64URL安全编码后的“ payload.
  • 一个 secret 密钥。
  • 通过 header 中指定的加密算法将 header.payload.secret 加密得到。

这儿需特别注意:secret 是保存在服务器端的,生成 token 也是在服务器端,所以一定不能泄露 secret ,如果泄露不法分子就能伪造 token 来攻击你的应用。

2.JWT的简单使用。

我们已经知道 jwt 是一种认证的字符串,那它认证的整个流程是怎么会是呢?我们先来看看官方给出的流程图。

通过流程图可以知道整个认证的流程分为6个动作:

  • 客户端用户正常的登陆。
  • 如果登陆成功服务器就生成 token
  • 服务器生成的 token 返回到客户端,客户端保存。
  • 下次请求服务器的时候在 HTTP 头部带上 token
  • 服务器验证 token 值是否正确。
  • 服务器通过验证得到的结果来给客户端返回对应的结果。

下面就用代码来实现一下这个流程(这儿仅仅只是一个用于展示原理的伪代码,正真项目中是不能这么写的)。

  • jwtHandle.php
<?php

//base64Url安全编码
function base64UrlEncode($data){
        $base64 = base64_encode($data);
        $base64Url = str_replace('=','',$base64);
        return $base64Url;
}

//base64Url解码

function base64UrlDecode($data){
    $len = strlen($data)%4;
    $addLen = 4 - $len;
    for($i=0; $i<$addLen; $i++){
        $data .= '=';
    }
    return base64_decode($data);
}

//生成header
function getHeader($type='jwt',$alg = 'hs256'){
    return json_encode([
        'type' => $type,
        'alg' => $alg,
    ]);
}

//生成replod
function getReplod($name){
    return json_encode([
        'name' => $name,
        'time' => strtotime("+1 hours"),
    ]);
}

//获取存在服务器中的密钥
function getSecret(){
    return '这儿是一串密钥,保存在服务器端,不能泄露';
}

//获取加密规则
function getHashingAlgorithm($alg){
    if(strcasecmp($alg, 'HS256') == 0){
        return 'sha256';
    }
}

//生成token
function createToken($header =[],$repload=[],$secret){

    $alg = getHashingAlgorithm(json_decode($header)->alg);
    $headerBase64Url = base64UrlEncode($header);
    $payloadBase64Url = base64UrlEncode($repload);
 
    $signature = hash_hmac($alg, $headerBase64Url . '.' . $payloadBase64Url, $secret);

    return $headerBase64Url . '.' . $payloadBase64Url . '.' . $signature;
}

//检查token
function checkoutToken($token,$secret){
    $jwtArr = explode('.',$token);
    $header = json_decode(base64UrlDecode($jwtArr[0]));
    $alg = getHashingAlgorithm($header->alg);

    $requestSignature = hash_hmac($alg, $jwtArr[0].'.'.$jwtArr[1], $secret);

    if(strcmp($jwtArr[2], $requestSignature) == 0){
        return json_decode(base64UrlDecode($jwtArr[1]))->name .'欢迎回来!';
    }else{
        return 'token 无效';
    }
}
  • JwtLogin.php
<?php
require 'jwtHandle.php';


$userName = 'superSnail';
$password = 'superSnail';

$requestName = $_POST['name'];
$requestPassword = $_POST['password'];

if($userName == $requestName && $password == $requestPassword){
    $header = getHeader();
    $repload = getReplod($requestName);
    $secret = getSecret();
    $token = createToken($header,$repload,$secret);
    echo '登陆成功,你的token是:'.$token.'。你好好的保存哦。';

}
  • checkToken.php
<?php
require 'jwtHandle.php';

$token = $_POST['token'];
$secret = getSecret();

$checkResult = checkoutToken($token,$secret);    
echo $checkResult;

客户端代码就是第一次带上用户名密码去请求登陆接口获取token,后面每次请求都检查有没有token,由就带上去请求接口。代码在此我就不赘述,感兴趣的同学自己下去写。下面我用postman来测试一下。

  • 测试登陆获取 token

  • 登陆通过后每次请求带上 token

当然,上边的代码我只是简单的阐述了这个工作的流程,实际应用中我们还需要考虑很多东西,比如说时间过期刷新 token等。

三.使用JWT的好处。

传统的web保持会话使用的 session 来实现的,session 我认为就类似一个组键值对类型的数据,然后这个数据存放这用户的登陆以及其它信息在键值对中以 value 的形式存在在服务器中,而对应键值对的 key 就是存放在客户端中的 cookie中,然后客户端每次登陆都会带上 cookie ,然后再服务器中通过 cookie 中的 key 来查找对应的 val。这样就实现了认证。

但是这样做有确定,我现在能自己想到的就是:

  • 如果用户量太大了,那么存在服务器中的 session 数据也会随之变得很大,浪费内存。
  • 如果用户量太大了,每次请求都会再服务器中计算对应的 session , 会浪费很多服务器的性能。
  • 如果某个产品的服务器不仅一台,比如说用了负载均衡,如果在某一台服务器中有过认证,但是如果下一次的请求到了不同的服务器,那么认证就会失败。
  • CSRF 跨站请求伪造的危险。

jwt 因为它自身的特性,就能够避免上述的缺点。

下一篇博客我将会讲解如何在laravel中使用 JWT 认证服务。

Snail's Blog
请先登录后发表评论
  • 最新评论
  • 总共0条评论
  • 本博客使用免费开源的 laravel-bjyblog v5.5.1.3 -develop 搭建 © 2014-2018 www.snail-c.cn 版权所有 ICP证:蜀ICP备18023253号-1
  • 联系邮箱:459921737@qq.com