国家虚拟仿真实验教学项目共享平台(实验空间)PHP SDK

使用XJWT标准,此标准基于JSON Web Token (JWT)开发。XJWT包含三个参数:header, payload, signature,因此生成token就要先获得这三个参数。

class IlabJwt
{
    public $TYPE_RESERVED = 0;
    public $TYPE_JSON = 1;
    public $TYPE_SYS = 2;
    
    public static $enableLog  = true;
    public static $logger  = null;
    
    public $appName       = 'test';
    public $issuerId   = 100400;
    public $secretKey  = '16jmp2';
    public $aesKey       = 'SbYymvfZ8UjEmShxRAB0b1Dtaa0uGjDOOJa/f0Mbuo4=';


    public  function is_64bit()
    {
        $int = "9223372036854775807";
        $int = intval($int);
        if ($int == "9223372036854775807") {
            /* 64bit */
            return 'J';
        }elseif ($int == 2147483647) {
            /* 32bit */
            exit('请使用64位的 PHP');
        }else{
            /* error */
            return 'error';
        }
    }
    
    public  function getJwt($body)
    {
        $body = json_encode($body, JSON_UNESCAPED_UNICODE);    //JSON_UNESCAPED_UNICODE 必须
        $header = $this->packHeader();
        $body = $this->encrypt($body);
        $base64Header = base64_encode($header);
        $base64Payload = base64_encode($body);
        $base64Signature = base64_encode($this->sign($base64Header, $base64Payload));
        $xjwt = urlencode($base64Header.'.'.$base64Payload.'.'.$base64Signature);
        return $xjwt;
    }
    
    public  function packHeader()
    {
        $header = '';
        $expiry = round((microtime(true) + 900) * 1000);    //900秒过期时间
        $header .= pack($this->is_64bit(), $expiry);
        $type = pack('n', $this->TYPE_JSON);
        $header .= $type[1];
        $header .= pack($this->is_64bit(), $this->issuerId);
        return $header;
    }
    
    public  function encrypt($body)
    {
        $payload = '';
        //前接8字节随机整数
        $randLong = pack($this->is_64bit(), rand(0, PHP_INT_MAX));
        $payload .= $randLong;
        $payload .= $body;
        //补齐为64字节的整数倍
        $tempLen = strlen($payload) + 1;
        $paddingLen = 16 - $tempLen % 16;
        $padding = str_pad('', $paddingLen + 1, pack('c', $paddingLen));
        $payload .= $padding;
        
        //aes加密
        $aesKey = base64_decode($this->aesKey);
        $iv = substr($aesKey, 0, 16);
        $payload = openssl_encrypt($payload, 'AES-256-CBC', $aesKey, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
        return $payload;
    }
    
    public  function sign($base64Header, $base64Payload)
    {
        $signature = hash_hmac('sha256', $base64Header . '.' . $base64Payload, $this->secretKey, true);
        return $signature;
    }
    
    public  function getBody($jwt)
    {
        list($base64Header, $base64Payload, $base64Signature) = explode('.', $jwt);
        $header    = base64_decode($base64Header);
        $payload   = base64_decode($base64Payload);
        $signature = base64_decode($base64Signature);
        if (!$this->validateSignature($signature, $base64Header, $base64Payload)) {
            // var_dump('Signature is invalid.');
            var_dump('Signature is invalid.');
            return 'error:Signature is invalid.';
        }

        //header:expiry
        $expiry = substr($header, 0, 8);
        if ($this->isExpired($expiry)) {
            var_dump('Data is expired.');
            return 'error:Data is expired.';
        }
        
        //header:type
        $type = substr($header, 8, 1);
        if (!$this->isValidType($type)) {
            var_dump('Type is invalid.');
            return 'error:Type is invalid.';
        }
        
        //header:issuerid
        $issuerId = substr($header, 9);
        if (!$this->isValidIssuer($issuerId)) {
            var_dump('Issuer is invalid.');
            return 'error:Issuer is invalid.';
        }
        
        //payload
        $body = $this->decrypt($payload);
        if (!$body) {
            return 'error:The wrong payload';
        }

        //['id' => xxx, 'un' => 'xxx', 'dis' => 'xxx']
        return json_decode($body, true);
        
    }

    public  function isExpired($expiry)
    {
        $expiry = unpack($this->is_64bit(), $expiry);
        $expiry = $expiry[1] / 1000;
        var_dump('Expiry : ' . date("Y-m-d H:i:s",intval($expiry)));
        return (time() < $expiry);
    }
    
    public  function isValidType($type)
    {
        $type = unpack('n', "\0" . $type);
        $type = $type[1];
        var_dump('Type : ' . $type);
        return $type === $this->TYPE_JSON;
    }
    
    public  function isValidIssuer($issuerId)
    {
        $issuerId = unpack($this->is_64bit(), $issuerId);
        $issuerId = $issuerId[1];
        var_dump('IssuerId : ' . $issuerId);
        return $issuerId === $this->issuerId;
    }
    
    public  function decrypt($payload)
    {
        $aesKey = base64_decode($this->aesKey);
        $iv = substr($aesKey, 0, 16);
        $data = openssl_decrypt($payload, 'AES-256-CBC', $aesKey, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
        $dataLen = strlen($data);
        $paddingLen = unpack('n', "\0" . $data[$dataLen - 1]);
        $paddingLen = $paddingLen[1];
        $body = substr($data, 8, - $paddingLen - 1);
        var_dump('Body : ' . $body);
        return $body;
    }
    
    public  function validateSignature($signature, $base64Header, $base64Payload)
    {
        $caculatedSignature = $this->sign($base64Header, $base64Payload);
        var_dump('Caculated signature (base64 code) : ' . base64_encode($caculatedSignature)
                . ', received signature (base64 code) : ' . base64_encode($signature));
        return (base64_encode($caculatedSignature) === base64_encode($signature));
    }
    
    public  function log($message, $type = 'info', $errno = null, $error = '', $file = null)
    {
        return;
    }
}

 

使用方法:

$token = (string)$_GET['token'];
$ilab = new IlabJwt();
$result = $ilab->getBody($token);
var_dump($result); #技术支持 方倍工作室

 

示例:

http://www.fangbei.org/tests/Ilab.php?token=AAABbRVKvGoBAAAAAAABiDA%3D.FN8Stlr2dWWsswAOq%2FlcJSboAOwzXGSb0nzPV7Ek1eiDBRJOT%2BZgllMiIwI4CtylOMrs6TaIW2HIeRxEqpwdM79SBpwuRbiyW4mLudHVrsHm1v2A7z1DYaUHpMZK%2BGF3u2l6CzMGTDvsQgOL4TUxPYwSN6%2FpC8k1szv36UIPAXydfK9vfDCIE%2FpwIU6XJVOrGGT8AFVfxNWn40%2FYDUTfpzoI8Cd09ZpxFqIxu8cQFu%2FhMDfUZ5F1jk2y%2FUOUW0zMR62SnVRKCr8YGUQV39oNlCQRSYrzJApXfpeVJNC1%2FyomujpfWWReJLP1QiMKnzoDARhAhRL%2BtODL1yXQQoUIJg%3D%3D.qmxiLXrOBDMVSInTgs%2B944v7Jf9YZ8stPAcEubfvCgQ%3D

返回

array(5) {
  ["id"]=>
  int(854)
  ["un"]=>
  string(5) "test4"
  ["dis"]=>
  string(18) "实验空间测试"
  ["orderId"]=>
  string(0) ""
  ["key"]=>
  string(172) "6bvL4uSUhZPCpKaSa8hA400uusujXi8HqP/dTRFjWA6EoSOBjnXzIcg9C0DhG6SaHYbSDuoX6pTvnIbP6wDGm2tjZClJNxpPLHR693dznJCBrwi7hFRlFeSdehBuE+BMRc1NDWoXNCEeDXbrOs2UblO5UqMbGk+WRL3gudRnIlw="
}

 

posted @ 2019-09-17 20:40 方倍工作室 阅读(...) 评论(...) 编辑 收藏