今天在做一个需求是用 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