2017年10月27日 星期五

Firebase 開發筆記 - 使用 PHP 之 Verify ID tokens using a third-party JWT library

PHP 漸漸地越來越沒有愛了 XD Ubuntu server 預設還是停留在 php5.5 系列,而許多套件都進入了 PHP 7 世界了。不知是不是這樣子,所以官方沒再推出 PHP SDK ?於是乎,只好自己刻一下下。也順勢認識 JWT,第一次認識是在 APNs Auth Key 的使用,沒想到這麼快又要上戰場了 XD

網路資源:
若覺得很煩,就直接用 https://github.com/kreait/firebase-php 吧!這篇專注在紀錄 JWT - Firebase 的使用和驗證。

用法:

$ mkdir jwt-3.2.2 ; cd jwt-3.2.2 ; composer require lcobucci/jwt
$ vim test.php
<?php
require 'vendor/autoload.php';

$token_string = 'XXXXXXXXXXX';

$signer = new Lcobucci\JWT\Signer\Rsa\Sha256();
$keychain = new Lcobucci\JWT\Signer\Keychain;
$parser = new Lcobucci\JWT\Parser;

try {
$token = $parser->parse($token_string);
} catch( Exception $e ) {
echo "decode failed\n";
exit;
}

// check key field
foreach (array( 'iat', 'exp', 'aud', 'iss', 'user_id' ) as $field) {
if (!$token->hasClaim($field)) {
echo "no $field\n";
exit;
}
}

if ($token->isExpired()) {
echo "exp expired\n";
exit;
}

if (!$token->hasHeader('kid')) {
echo "no kid\n";
exit;

}
$kid = $token->getHeader('kid');

$keys = json_decode(file_get_contents('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com'), true);

if (!isset($keys[$kid])) {
echo "kid not found\n";
exit;
}


try {
if( $token->verify($signer, $keychain->getPublicKey($keys[$kid])) )
echo "PASS\n";
} catch (Exception $e) {
echo "Failed";
}

$user_id = $token->getClaim('user_id');


連續動作(PHP Codeigniter Usage):

$ cat Jwt_library.php
<?php
require_once 'jwt-3.2.2/vendor/autoload.php';
class Jwt_library {
public function __construct() {
$this->ci = &get_instance();
$this->parser = new Lcobucci\JWT\Parser;
$this->keychain = new Lcobucci\JWT\Signer\Keychain;
$this->signer = new Lcobucci\JWT\Signer\Rsa\Sha256;
}

public function verify_firebase_token(&$error, $user_token, $project_id, $service_public_keys = array()) {
$user_id = NULL;
$error = NULL;
$token = false;
try {
$token = $this->parser->parse($user_token);
} catch (Exception $e) {
$error= 'decode failed';
return NULL;
}

// check filed name
foreach (array( 'iat', 'exp', 'aud', 'iss', 'user_id' ) as $field) {
if (!$token->hasClaim($field)) {
$error = "no $field";
return NULL;
}
}

if ($token->isExpired()) {
$error = 'exp expired';
return NULL;
}
//if ($token->getClaim('iat') > time() )
// return 'token has been issued in the future';

if ($token->getClaim('aud') != $project_id ) {
$error = 'aud error';
return NULL;
}

$user_id = $token->getClaim('user_id');

$kid = false;
try{
$kid = $token->getHeader('kid');
} catch (Exception $e) {
$error = 'no kid';
return NULL;
}

if (!isset($service_public_keys[$kid])) {
$error = 'kid not found: '.$kid;
return NULL;
}

try {
if ($token->verify($this->signer, $this->keychain->getPublicKey($service_public_keys[$kid])))
return $user_id;
} catch (Exception $e) {
$error = 'verify failed';
}

return NULL;
}
}


$ cat php_ci_controller.php
<?php
$output = array( 'status' => false );

$authorization_info = $this->input->get_request_header('Authorization', True);
if (empty($authorization_info) || strstr($authorization_info, 'Bearer ') == false) {
        $output['error'] = -1;
        $output['message'] = 'no Authorization';
        $this->_json_output($output);
        return;
}

$firebase_user_token = trim(substr($authorization_info, strlen('Bearer ')));
$this->load->library('jwt_library');
$keys = @json_decode(@file_get_contents('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com'), true);
$firebase_user_id = $this->jwt_library->verify_firebase_token($verify_error, $firebase_user_token, 'YourFirebaseProjectId', $keys);
if (empty($firebase_user_id)) {
$output['error'] = 1;
$output['message'] = 'verify: '.$verify_error;
$this->_json_output($output);
return;
}

沒有留言:

張貼留言