網路資源:
- https://firebase.google.com/docs/auth/admin/verify-id-tokens
- https://jwt.io/
- https://github.com/lcobucci/jwt/tree/3.2 (因應 PHP 5.x 使用 3.2.2版)
- https://github.com/kreait/firebase-php
用法:
$ 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;
}