php使用JWT生成Token

一 . JWT 即 Json Web Token。
随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。

jwt 主要由消息头header 和 数据载体组成。消息头 header是由6个 标准消息体 key=>value 键值对组成,其中key是固定的不能更改,用户可根据自己的实际情况选择需要的部分 header。消息载体 payload [key=>value]数组,完全是由用户自定义。

"iss" => "http://example.org", // jwt签发者 "sub" => "1234567890", // jwt所面向的用户 "aud"=>"",// 接收jwt的一方 "exp"=>$time+10,//: jwt的过期时间,这个过期时间必须要大于签发时间 "nbf"=>$time, //: 定义在什么时间之前,该jwt都是不可用的. "iat"=>$time, //: jwt的签发时间 "jti"=>"",//: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 // 消息载体 "data"=>[ "userid"=>12, "isBoss"=>1, . . . . . . 在本人实际开发中, 用的比较多的是 iat, exp 两个消息头。

二 . php生成jwt
php生成jwt可以有两种途径 composer库 lcobucci/jwt & pecl库cdoco/php-jwt最新版1.0.0

pecl cdoco/php-jwt 扩展的使用:
打开 https://github.com/cdoco/php-jwt 如果你的php 版本是5 ,可选择当前主分支 0.2.5 。如果你是 php7,请切换到分支v1.0.0 ( https://github.com/cdoco/php-jwt/tree/v1.0.0 ) 下载安装。
下面以安装 php7版本的 jwt v1.0.0 版本和基本使用案例

$ cd ~/php-extension $ wget https://github.com/cdoco/php-jwt/archive/v1.0.0.zip $ unzip v1.0.1.zip #得到 php-jwt-1.0.0/ $ cd php-jwt-1.0.0/ $ vi php_jwt.h # 修改该文件的版本号,可忽略 (个人习惯会修改一下) 找到 #define PHP_JWT_VERSION 配置项 将后面的值 改成 "1.0.0" 然后保存退出 $ /usr/local/php/bin/phpize $ ./configure --with-php-config=/usr/local/php/bin/php-config $ make && make install # 根据结果提示查看是否安装完成 $ vi php.ini # 在追后追加 extension = jwt.so 保存退出 $ php --ri jwt # 查看 扩展版本号是否为 1.0.0 $key = "Your custom encrypt key"; $time = time(); $payload = array( "data" => [ "name" => "ZiHang Gao", "admin" => true //"iss" => "http://example.org", // jwt签发者 //"sub" => "1234567890", // jwt所面向的用户 //"aud"=>"",// 接收jwt的一方 "exp"=>$time+10,//: jwt的过期时间,这个过期时间必须要大于签发时间 //"nbf"=>$time, //: 定义在什么时间之前,该jwt都是不可用的. "iat"=>$time, //: jwt的签发时间 //"jti"=>"",//: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 // 生成 jwt token $token = \Cdoco\JWT::encode($payload, $key); // ...... end // 解析你的 jwt token $data = \Cdoco\JWT::decode($token, $key); var_dump($data); }catch (Exception $e){ get_class($e) == "SignatureInvalidException"; // 表示 token 被串改或 加密的 key 被串改 get_class($e) == "ExpiredSignatureException"; // 表示 token 过期 get_class($e) == "BeforeValidException"; // 表示 token 在规定之前的时间内不允许使用 var_dump(get_class($e)); var_dump($e->getMessage());

composer lcobucci/jwt的基本使用

安装: composer require lcobucci/jwt
 * 生成 jwt
 * @param array $data 消息载体
 * @param int $expire 过期有效时间
 * @param string $secertKey 加密key
 * @return string jwtToken
function generateJwt(array $data,string $secertKey="", int $expire=0):string {
        $signer = new Sha256();
        $currentTime = time();
        $secert = $secert ? : "Your custom encrypt key"; 
        $builder = new Builder();
        if ($expire){
            $builder->expiresAt($currentTime + $expire); //添加过期时间,无过期时间表示永远有效
        $token = $builder
            ->canOnlyBeUsedAfter($currentTime) //多少秒前该token无法使用
            ->withClaim("data", $data) //设置数据
            ->getToken($signer, new Key($secert));
        $token = strval($token);
        return (string)$token;
  * 解析你的 jwt token
  * @param string $token 你要解析的 jwtToken 字符串
  * @param string $secret 你的加密 key ,必须与生成token的加密key一致
  * @return array 原jwt的header和payload组成的数组
function parseJwt(string $token,string $secert=""):array{
        $secert = $secert ? : "Your custom encrypt key";
        $signer = new Sha256();
            $token = (new Parser())->parse($token);
            if ($token->verify($signer, $secert)) { //验证token是否被串改或加密的key错误
                $validation = new ValidationData();
                $data = (array)$token->getClaim("data"); // 得到消息载体
                if(empty($data)){
                   throw new Exception("empty data"); // 该情况,表示拥护在生成 jwt的时候,没有放入载体。
                    // 该情况一般不会发生,
                if(!$token->validate($validation)) {
                    throw new Exception("expire"); // 抛出 token过期的异常
            }else{
                throw new Exception("failed"); // 抛出 token是被串改或加密的key错误的异常
        }catch (\Exception $exception){
            // 当 jwt 解析异常的时候,会出现异常,例如Token过期, secret错误等等