今天遇到个坑,记录一下。
在记录之前,还是要补充装环境的坑。
前段时间记录了一下ThinkPhp5不知道多少,开发环境是macos11,因为macos自带apache,php开发环境,直接把apache的配置文件的http.conf里的php开关打开即可。但是换了设备,开发环境是macos12,系统自带的apache把php去掉了,所以配置php环境,除了安装php,还在apache的http.conf文件添加php运行路径,还要倒入相关模块,还要使用证书对http.con文件进行签名(我到这一步就放弃了,因为我没找到那个证书签名)。那只能换一种方式了,就是使用brew安装php,然后还要安装httpd,还要在其配置文件添加运行环境和导入模块(具体可以参考这个)。
还要配置环境

export PATH="/usr/local/opt/php@7.4/bin:$PATH"
export PATH="/opt/homebrew/bin:$PATH"

还要安装composer工具包安装工具。

brew install composer

安装好之后,可以创建一个php项目。

composer create-project topthink/think=版本号 项目名称

好的,那么再记录一下今天这个坑。
因为换电脑,我把代码上传到了gitee,然后把代码拉下来,然后就跑不起来了,奇奇怪怪。
主要还是那个Firebase\JWT\JWT 这个包,JWT的encode 和 decode 和之前的有区别。
先对比一下前后的代码

先前的代码

 private static function generateToken($data){$key = 'key';   //秘钥:自定义$payload = array('iss' => 'my',                      //签发人(官方字段:非必需)'aud' => 'public',                    //受众(官方字段:非必需)'iat' => time(),                      //签发时间'nbf' => time(),                      //生效时间,立即生效'exp' => time() + 60*60*24*7,         //过期时间,一周'data' => $data,                        //自定义字段);//加密生成tokenreturn JWT::encode($payload, $key);}public static function checkToken($request){$authorization = $request->header("authorization");// 获取token{// 异常捕获无效try {$token = substr($authorization,8,-1);}catch (\Exception $ex){$token = $authorization;}}try {// 1.如果当前时间大于 exp,或者小于nbf,token无效,进行拦截$key = 'key';JWT::$leeway = 60;//当前时间减去60,把时间留点余地$decode = JWT::decode($token, $key, array('HS256'));// 查数据库,用户不存在if(Users::where('uid', $decode->data)->find()){// 比较当前时间大于 exp,或者小于nbf,token无效,进行拦截if($decode->nbf > time()){return "权限伪造!";}elseif ($decode->exp < time()){return "权限过期,请重新登录!";}}else{return "账户不存在!";}}catch (\Exception $ex){// token 无效return "权限不足!";}return true;}

之后的代码

private static function generateToken($data): string{$key = 'key';   //秘钥:自定义$payload = array('iss' => 'my',                      //签发人(官方字段:非必需)'aud' => 'public',                    //受众(官方字段:非必需)'iat' => time(),                      //签发时间'nbf' => time(),                      //生效时间,立即生效'exp' => time() + 60*60*24*7,         //过期时间,一周'data' => $data,                        //自定义字段);$keyId = "keyId";//加密生成tokenreturn JWT::encode($payload, $key, 'HS256', $keyId);}public static function checkToken($request){$authorization = $request->header("authorization");// 获取token{// 异常捕获无效try {$token = substr($authorization,7);}catch (\Exception $ex){$token = $authorization;}}try {// 1.如果当前时间大于 exp,或者小于nbf,token无效,进行拦截JWT::$leeway = 60;//当前时间减去60,把时间留点余地// ==========================主要是下面这一段================================$key = new Key('key', 'HS256');$decode = JWT::decode($token, $key);// ==========================主要是上面面这一段================================// 查数据库,用户不存在if(Users::where('uid', $decode->data)->find()){// 比较当前时间大于 exp,或者小于nbf,token无效,进行拦截if($decode->nbf > time()){return "权限伪造!";}elseif ($decode->exp < time()){return "权限过期,请重新登录!";}}else{return "账户不存在!";}}catch (\Exception $ex){// token 无效echo $ex;return "权限不足!";}return true;}

把前后两段代码的关键部分揪出来对比一下:

# encode
$key = 'key';   //秘钥:自定义
$payload = array(...);
return JWT::encode($payload, $key);
# decode
$key = 'key';
JWT::$leeway = 60;//当前时间减去60,把时间留点余地
$decode = JWT::decode($token, $key, array('HS256'));
===================================================================
# encode
$key = 'key';   //秘钥:自定义
$payload = array(...);
$keyId = "keyId"; //这个东西必须要加上,不加上,报错,报错内容:'"kid" empty, unable to lookup correct key'
//加密生成token
return JWT::encode($payload, $key, 'HS256', $keyId);
# decode
JWT::$leeway = 60;//当前时间减去60,把时间留点余地
$key = new Key('key', 'HS256'); // 必须是 Firebase\JWT\Key;的对象
$decode = JWT::decode($token, $key);

分析一下源码
主要是这里的$keyId,这个参数给了个初始值null,把这个值$header[‘kid’] = $keyId;,但是在解码的时候,必须要有值,既然要求解码必须有值并且不为null,那个这里就不给出初始值,给开发者来传参就好了,这样友善一点。

public static function encode(array $payload,$key,string $alg,string $keyId = null,array $head = null): string {$header = ['typ' => 'JWT', 'alg' => $alg];if ($keyId !== null) {$header['kid'] = $keyId; // 这里给$header['kid']赋值了,kid出错,原因在这}if (isset($head) && \is_array($head)) {$header = \array_merge($head, $header);}$segments = [];$segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header));$segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload));$signing_input = \implode('.', $segments);$signature = static::sign($signing_input, $key, $alg);$segments[] = static::urlsafeB64Encode($signature);return \implode('.', $segments);}
public static function decode(string $jwt,$keyOrKeyArray): stdClass {// Validate JWT$timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;if (empty($keyOrKeyArray)) {throw new InvalidArgumentException('Key may not be empty');}$tks = \explode('.', $jwt);if (\count($tks) != 3) {throw new UnexpectedValueException('Wrong number of segments');}// 对token进行了切分,分成了三部分list($headb64, $bodyb64, $cryptob64) = $tks;$headerRaw = static::urlsafeB64Decode($headb64);if (null === ($header = static::jsonDecode($headerRaw))) {throw new UnexpectedValueException('Invalid header encoding');}$payloadRaw = static::urlsafeB64Decode($bodyb64);if (null === ($payload = static::jsonDecode($payloadRaw))) {throw new UnexpectedValueException('Invalid claims encoding');}if (\is_array($payload)) {// prevent PHP Fatal Error in edge-cases when payload is empty array$payload = (object) $payload;}if (!$payload instanceof stdClass) {throw new UnexpectedValueException('Payload must be a JSON object');}$sig = static::urlsafeB64Decode($cryptob64);if (empty($header->alg)) {throw new UnexpectedValueException('Empty algorithm');}if (empty(static::$supported_algs[$header->alg])) {throw new UnexpectedValueException('Algorithm not supported');}// 主要是这里,要求$header->kid 不为null,值为null就报错。$key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null);// 这里对$key 要求是 Firebase\JWT\Key ,不然 没有getAlgorithm()()方法就拿不到Algorithm值// Check the algorithmif (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) {// See issue #351throw new UnexpectedValueException('Incorrect key for this algorithm');}if ($header->alg === 'ES256' || $header->alg === 'ES384') {// OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures$sig = self::signatureToDER($sig);}// 这里对$key 要求是 Firebase\JWT\Key ,不然 没有getKeyMaterial()方法就拿不到Material值if (!self::verify("$headb64.$bodyb64", $sig, $key->getKeyMaterial(), $header->alg)) {throw new SignatureInvalidException('Signature verification failed');}// Check the nbf if it is defined. This is the time that the// token can actually be used. If it's not yet that time, abort.if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) {throw new BeforeValidException('Cannot handle token prior to ' . \date(DateTime::ISO8601, $payload->nbf));}// Check that this token has been created before 'now'. This prevents// using tokens that have been created for later use (and haven't// correctly used the nbf claim).if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) {throw new BeforeValidException('Cannot handle token prior to ' . \date(DateTime::ISO8601, $payload->iat));}// Check if this token has expired.if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {throw new ExpiredException('Expired token');}return $payload;}

ThinkPhp5.0.24 JWT报错 ‘“kid“ empty, unable to lookup correct key‘解决办法相关推荐

  1. Firebase token认证 “kid“ invalid, unable to lookup correct key

    解码时, use Firebase\JWT\JWT; use Firebase\JWT\Key; JWT::decode($jwt, $key, ['HS256']); 改为 JWT::decode( ...

  2. Navicat 远程连接docker容器中的mysql 报错1251 - Client does not support authentication protocol 解决办法

    Navicat 远程连接docker容器中的mysql 报错1251 - Client does not support authentication protocol 解决办法 1).容器中登录my ...

  3. [转载] 树莓派4B使用 Adafruit_PCA9685 报错IOError: [Errno 121] Remote I/O error解决办法

    参考链接: Python文件I / O 树莓派4B使用 Adafruit_PCA9685 报错IOError: [Errno 121] Remote I/O error解决办法 首先,确保已经下载了p ...

  4. Zookeeper报错Will not attempt to authenticate using SASL解决办法

    Will not attempt to authenticate using SASL (unknown error) 经过查资料,这个问题与zookeeper里面的zoo.cfg配置有关. 在程序填 ...

  5. 报错:Could not find action or result解决办法

    报错:Could not find action or result解决办法 $("#btn-processSubmit").click(function(){if(status ...

  6. 【报错解决】linux网络编程报错storage size of ‘serv_addr’ isn’t known解决办法

    linux网络编程报错storage size of 'serv_addr' isn't known解决办法 报错如下: server.c:18:21: error: storage size of ...

  7. oracle ogg00423,【案例】Oracle报错PLS-00378 PLS-00439产生原因和MOS官方解决办法

    [案例]Oracle报错PLS-00378 PLS-00439产生原因和MOS官方解决办法 时间:2016-11-12 21:31   来源:Oracle研究中心   作者:代某人   点击: 次 天 ...

  8. 浏览器报错Not allowed to load local resource:的解决办法,与网上大多数都不同,亲测有用!

    浏览器报错Not allowed to load local resource:的解决办法,与网上大多数都不同,亲测有用! 起因 报错原因 吐槽 解决办法 参考 起因 因为深度学习用的是pytorch ...

  9. php数据库报错1046怎么解决,DZ报错MySQL Query Error Errno:1046错误的解决办法

    这篇文章主要为大家详细介绍了DZ报错MySQL Query Error Errno:1046错误的解决办法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,有需要的朋友可以收藏方便以后借鉴. DZ报 ...

最新文章

  1. SDNU 1406.A+B问题(水题)
  2. navicat开启mysql数据库root用户的远程访问
  3. JAVA代码覆盖率工具JaCoCo-原理简单分析
  4. android 模拟器read-only file system,WAC启动Android模拟器 transfer error: Read-only file system错误解决方法...
  5. 怎么看mmdetection版本_如何评价商汤开源的 mm-detection 检测库?
  6. 智能优化算法:适应度相关优化算法 - 附代码
  7. 编译OpenCV缺少python27_d.lib的解决方法
  8. jQuery按住滑块拖动验证插件
  9. C++ 重制植物大战僵尸(Cocos2dx开源项目)
  10. php网站 怎么查是否开源,怎么查看网站的开源程序?
  11. ipad服务器响应超时,iPad Air连接iTunes设备超时
  12. 新华三:照耀城市的数字演进之路
  13. 从 Illustrator 怎么导入 Glyphs?
  14. 【MySQL数据库】笔试题总结
  15. 推荐系统领域对比学习和数据增强论文及代码集锦
  16. ISIS 防环机制分析
  17. 在 Adob​​e MAX 深入研究 UI/UX 设计
  18. via ladder
  19. 银行核心系统如何选型分布式数据库(含6大落地要点验证)
  20. php+mysql 商品报价系统 学生适用

热门文章

  1. MSP430系列单片机实用C语言程序设计 张晞pdf
  2. 51 币圈里外的强者愈强----超级君扯淡录【2020-07-13 2100】
  3. 2019年中国幼儿园数量、幼儿园入园率、幼儿园政策及幼儿园市场规模发展趋势分析[图]
  4. 手动清除2345流氓主页小记录以及对过去的一些回忆
  5. 自动更新word题注
  6. android studio manifest merger failed,android studio 引用第三方工程Manifest merger failed
  7. linux系统安装hba驱动,Linux系统上iSCSI HBA的安装和配置
  8. 我叫mt4最新服务器,我叫mt4什么时候开新区 开服时间表
  9. (中级)系统集成项目管理工程师常用英语汇总
  10. 7-7 厘米换算英尺英寸 (10分)