'HS256', //生成signature的算法 'typ' => 'JWT', //类型 'source' => 'panda_fat' //第三方唯一名称 ]; //使用HMAC生成信息摘要时所使用的密钥 private static string $key = 'xv0CTimwzot8ITC4Z0cwGMV54eI5lUHG'; private static int $exp = 30 * 24 * 60 * 60; /** * 获取jwt token * @param array $data //参数 * @param iss //该JWT的签发者 * @param iat //签发时间 * @param exp //过期时间 * @param nbf //该时间之前不接收处理该Token * @param sub //面向的用户 * @param jti //该Token唯一标识 * @return false|string */ /** * @param array $data * [ * iss //该JWT的签发者 * iat //签发时间 * exp //过期时间 * nbf //该时间之前不接收处理该Token * sub //面向的用户 * jti //该Token唯一标识 * ] * @return bool|string * @throws \Exception */ public static function getToken(array $data = []): bool|string { $payload = [ 'iss' => 'joeyoung0314@qq.com', 'iat' => time(), 'exp' => time() + self::$exp, 'nbf' => time() + 60, 'jti' => md5(uniqid('JWT') . time()), 'data' => $data ]; $base64header = self::base64UrlEncode(json_encode(self::$header, JSON_UNESCAPED_UNICODE)); $base64payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE)); $token = $base64header . '.' . $base64payload . '.' . self::signature($base64header . '.' . $base64payload, self::$key, self::$header['alg']); //设置唯一token RedisUtil::getInstance(RedisKeyEnum::TOKEN_ONCE,md5(json_encode($data)))->setex(md5($token),self::$exp); return $token; } /** * 验证token是否有效,默认验证exp,nbf,iat时间 * * @param string $Token * @return false|mixed * @throws \Exception */ public static function verifyToken(string $Token) { //验证token $tokens = explode('.', $Token); if (count($tokens) != 3) return false; list($base64header, $base64payload, $sign) = $tokens; //获取jwt算法 $base64decode_header = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY); if (empty($base64decode_header['alg'])) return false; if (empty($base64decode_header['source']) || $base64decode_header['source'] != self::$header['source']) return false; //签名验证 if (self::signature($base64header . '.' . $base64payload, self::$key, $base64decode_header['alg']) !== $sign) return false; $payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY); if (!$payload || !isset($payload['data'])) return false; //校验token唯一性 $md5Token = RedisUtil::getInstance(RedisKeyEnum::TOKEN_ONCE,md5(json_encode($payload['data'])))->get(); if ($md5Token != md5($Token)) return false; return $payload; } /** * base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现 * @param string $input 需要编码的字符串 * @return string */ private static function base64UrlEncode(string $input): string { return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); } /** * base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现 * @param string $input 需要解码的字符串 * @return bool|string */ private static function base64UrlDecode(string $input): bool|string { $remainder = strlen($input) % 4; if ($remainder) { $add_len = 4 - $remainder; $input .= str_repeat('=', $add_len); } return base64_decode(strtr($input, '-_', '+/')); } /** * HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现 * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload) * @param string $key * @param string $alg 算法方式 * @return string */ private static function signature(string $input, string $key, string $alg = 'HS256'): string { $alg_config = [ 'HS256' => 'sha256' ]; return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key, true)); } }