每天学习一点点,成功增加一大步

PHP 笔记:使用 JWT 创建 Token

PHP zhanghui 1139℃

今天在做一个需求是用 PHP 创建一个 JWT 类型的 Token ,要问什么是 JWT 自己百度或谷歌去吧,这点功夫都懒得下的话就自己打自己一下吧。这回还是头一次遇到做这个需求,解决的过程还是有点头疼的,但成功之后就感觉到收获了。现将解决的过程记录下来。

依赖

  • 环境:php 5.5 以上 + OpenSSL扩展
  • lcobucci/JWT

非 windows 环境的可使用 composer 安装(因为我在是 Windows 环境下做的实验)

composer require lcobucci/jwt

我还是比较推荐直接到 GitHub 下载完整包比较稳妥。

GitHub 地址: https://github.com/lcobucci/jwt

下载时请注意:不要不加思索的就点【 Clone or download 】按钮,这样你下载的是 【master】分支的版本,这个版本虽然是最新的,但并不代表就稳定。

在这里我选择 3.2

参数解释

在使用之前先了解一下

名称 解释
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设置唯一标示

实例前准备

在写实例之前首先要阐述一下几点,因为这也是我在研究过程中遇到的坑。

在从 GITHUB 上面下载过来的完整包,其实并不完整,直接拿到项目中用会出现各个独立命名类之间的依赖没有引用语句,这个是要你自己加的。我不知道其他的环境是不是这样,至少我在 windows 中做研究是这样的。

下面记录主要的依赖引用:

define('DS', DIRECTORY_SEPARATOR);
define('JWTPath', dirname(__FILE__) . DS);
include_once JWTPath . 'Builder.php';
include_once JWTPath . 'Signer.php';
include_once JWTPath . 'Signer' . DS . 'Keychain.php';
include_once JWTPath . 'Signer' . DS . 'Rsa.php';
include_once JWTPath . 'Signer' . DS . 'Rsa' . DS . 'Sha256.php';

当然它们里面还有更多的引用需要你自己加,这个在你调试时根据错误提示一个个补就好了,这里就不多写了。

2018-10-31 记:还有一种可以解决上面所说的引用问题,那就量【spl_autoload_register】只因之前较少用所以没有发现它的存在,使用它也能解决上述问题,这也是后来发现的,但因工作上的原因没有及时做记载,今天发现了所以及时补上。代码如下:

spl_autoload_register(function ($class_name) {
    $class_name = substr($class_name, strlen('Lcobucci\\JWT\\'));
    $path = dirname(__FILE__) . DS . $class_name . '.php';
    /** @noinspection PhpIncludeInspection */
    !file_exists($path) ?: require_once $path;
//    echo $path . "\r\n";
});

实例

使用【lcobucci/JWT】产生 Token 的方式有两种,在这里我只试验了第二种。

第一种:使用秘钥签名生成 token

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
$builder = new Builder();
$signer = new Sha256();
// 设置发行人
$builder->setIssuer('http://example.com'); 
// 设置接收人
$builder->setAudience('http://example.org'); 
// 设置id
$builder->setId('4f1g23a12aa', true); 
// 设置生成token的时间
$builder->setIssuedAt(time()); 
// 设置在60秒内该token无法使用
$builder->setNotBefore(time() + 60); 
// 设置过期时间
$builder->setExpiration(time() + 3600); 
// 给token设置一个id
$builder->set('uid', 1); 
// 对上面的信息使用sha256算法签名
$builder->sign($signer, '签名key');
// 获取生成的token
$token = $builder->getToken();

验证 Token

use Lcobucci\JWT\Signer\Hmac\Sha256;
$parse = (new Parser())->parse($token);
$signer = new Sha256();
$parse->verify($signer,'签名key');// 验证成功返回true 失败false

第二种:使用RSA和ECDSA签名

RSA和ECDSA签名是基于公钥和私钥,所以必须使用私钥生成和验证使用

use Lcobucci\JWT\Signer\Keychain;
// 注意这里使用的sha256
use Lcobucci\JWT\Signer\Rsa\Sha256; 
$signer = new Sha256();
$keychain = new Keychain();
$builder = new Builder();
$builder->setIssuer('http://example.com');
$builder->setAudience('http://example.org');
$builder->setId('4f1g23a12aa', true);
$builder->setIssuedAt(time());
$builder->setNotBefore(time() + 60);
$builder->setExpiration(time() + 3600);
$builder->set('uid', 1);
// 与上面不同的是这里使用的是你的私钥,并提供私钥的地址
$builder->sign($signer, $keychain->getPrivateKey('file://{私钥地址}'));
$toekn = $builder->getToken();

最后还可以通过强制转换的形式来拿到你想要的纯字符串的 Token

$toekn = (string) $builder->getToken();

和前端的交互可以放在返回的 JSON 格式中通过参数带过去,也可以存放在 header Authorization 中。

验证 Token

$signer = new \Lcobucci\JWT\Signer\Rsa\Sha256();
$keychain = new \Lcobucci\JWT\Signer\Keychain();
$parse = new \Lcobucci\JWT\Parser();
$parse->parse((string)$token);
var_dump($token->verify($signer, $keychain->getPublicKey(self::$dir . '/public.key')));
))

获取数据

因为数据部分可以直接获取到,不用解密。所以在验证token合法后直接读取即可,这也是不要在载体中存放敏感信息的原因。

$parse = (new Parser())->parse($token);
// 获取全部信息,返回一个数组,
var_dump($parse->getClaims());
// 获取单条信息
var_dump($parse->getClaim('aud'));

验证有效性的工具:https://jwt.io/

在 GITHUB 上还有一种 PHP-JWT 资源:https://github.com/firebase/php-jwt

 

转载请注明:隨習筆記 » PHP 笔记:使用 JWT 创建 Token