JWT初探

 提示:转载请注明原文链接

 本文永久链接:https://360us.net/article/55.html

什么是JWT?

JWT全称是JSON Web Token,这是一个开放的RFC7519标准,它定义了在两者之间使用JSON安全传输数据的准则。

传输的数据是可信的,并且是可验证的,因为数据已经添加了数字签名。

签名可以用密钥或者是RSA密钥对签名。

有什么特性呢?

  • 体积比较小,可以作为URL,POST数据等的参数,也可以放在HTTP头里面传输。另一方面,小意味着传输比较快。

  • 里面包含的信息都是可以直接拿来用的,避免了去数据库查询。

什么时候应该使用JWT?

典型场景:

  • 身份验证:这个是JWT最常用的场景了。一旦用户登录,之后的请求都需要带上JWT信息,验证通过之后才能访问授权的资源。比如单点登录,手机APP接口等。

  • 信息交换:因为JWT的数据是签名之后的数据,这样可以保证安全。

JWT的数据结构

由三部分组成,每一个部分是用点(.)分割的:

  • Header(头);

  • Payload(数据);

  • Signature(签名)。

所以,典型的JWT数据格式看起来像这样:xxxxx.yyyyy.zzzzz

Header

头部包含两部分,token的类型,固定的JWT;哈希的算法,比如HMAC SHA256或者RSA。

一般hash256的名称是HS256,RSA算法的名称是RS256。

比如:

{  "alg": "HS256",  "typ": "JWT"}

然后用base64编码这个JSON,就组成了JWT的第一部分。

Payload

这一部分就包含了我们需要的具体信息(claims)了。

这里的数据又分为三种类型:保留的,公用的和私有的。

保留的: 预先定义的一组数据,不是必须的但是建议有。

比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等等。

注意,这一部分的数据名称只有三个字符。

公共的: 这一部分的数据是自定义的,但是要避免使用URL和JSON里面的特殊字符。

私有的: 使用双方共享的一些信息。

payload例子:

{  "sub": "1234567890",  "name": "John Doe",  "admin": true}

这部分数据是我们可以自定义的数据。

然后base64编码数据,作为JWT的第二部分。

Signature

把header和payload分别base64编码之后用点号(.)连接起来,再用header里面指定的算法签名。

如用用HMAC sha256加密:

hash_hmac('sha256', base64UrlEncode(header) . base64UrlEncode(payload), secret);

结果

最后把上面得到的三部分用点号(.)连接起来。

JWT如何工作的?

用户登录后,服务器会返回一个JWT字符串给用户,当访问受保护的资源的时候,需要把这个字符串传回来,验证通过之后才可以访问。

这个和session不同的地方就是,用户登录成功之后不用把认证信息存session,而是直接存在JWT里面,验证的时候从JWT里面解析出来拿来用就可以了。

比较适合用在APP API,单点登录等场景下面。

JWT一般放在HTTP的Authorization头里面,值的前面加上一个Bearer名称,如:Authorization: Bearer <token>

下面是一个交互图:

jwt-diagram.png

因为JWT是在http协议传输的,也有可能发在url里面,所以base64之后的有些特殊字符需要转换。看下面php实例的base64UrlEncode和base64UrlDecode函数。

PHP代码示例

可以到这里:https://jwt.io/验证结果正确与否。

class Jwt
{
    public function getToken()
    {
        $header =  $this->base64UrlEncode(json_encode([
            'alg' => 'HS256',
            'typ' => 'JWT',
        ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
        $payload =  $this->base64UrlEncode(json_encode([
            'id' => 123,
            'name' => 'xiaobai',
            'isAdmin' => true,
        ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
        $secret = '110';
        //这里用sha256签名的时候需要返回二进制数据,而不是十六进制字符串,所以第三个参数设置为true
        $sign = $this->base64UrlEncode(\hash_hmac('sha256', $header . '.' . $payload, $secret, true));
        echo "{$header}.{$payload}.{$sign}";
    }
    protected function base64UrlEncode($data)
    {
        return str_replace('=', '', strtr(base64_encode($data), '+/', '-_'));
    }
    protected function base64UrlDecode($data)
    {
        if ($remainder = strlen($data) % 4) {
            $data .= str_repeat('=', 4 - $remainder);
        }
        return base64_decode(strtr($data, '-_', '+/'));
    }
}


 评论
暂无评论