提问者:小点点

使用带有身份验证的PHP访问Firebase REST


我正在尝试使用PHP、谷歌身份验证库和Firebase REST的包装器从服务器访问Firebase…这非常适合实现这一点:

use Firebase\JWT\JWT;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Auth\HttpHandler\HttpHandlerFactory;
use GuzzleHttp\Client;

$email = 'account@email.com';
$key = 'private_key_goes_here';

$scopes = [
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/firebase.database',
];

$creds = [
    'client_email' => $email,
    'private_key' => $key,
];

$serviceAccount = new ServiceAccountCredentials($scopes, $creds);
$handler = HttpHandlerFactory::build(new Client());
$token = $serviceAccount->fetchAuthToken($handler);

$firebase = new \Firebase\FirebaseLib($url, $token);
$value = $firebase->get('test/hello');
# $value now stores "world"

但是,这要求Firebase中的安全规则是通用读/写,这是我不想要的。如果我将我的安全规则更新为:

{
  "rules": {
    "test": {
      ".read": "auth != null"
    }
  }
}

$value中的结果变为{"error":"权限被拒绝"}。我进行了广泛的搜索,并尝试了许多排列和可能的解决方案,但没有确凿的结果。

我使用这段代码向终端客户端提供了JWT令牌,终端客户端可以成功使用它们并毫无问题地利用安全规则。我最初在服务器上尝试了同样的方法,但没有成功。我选择尝试结合这两种方法:

# Snipping code that didn't change...
$serviceAccount = new ServiceAccountCredentials($scopes, $creds);
$handler = HttpHandlerFactory::build(new Client());

$payload = [
    'iss' => $email,
    'sub' => $email,
    'aud' => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
    'iat' => time(),
    'exp' => time() + 60 * 60,
    'uid' => '123',
    'claims' => [
        'uid' => '123',
    ],
];

$payload = $serviceAccount->updateMetadata($payload);
$token = JWT::encode($payload, $key, 'RS256');

$firebase = new \Firebase\FirebaseLib($url, $token);
$value = $firebase->get('test/hello');

这似乎很接近,但$value现在包含{"error":"在auth标头中缺少声明'亲子'。"}。为了解决这个问题,我修改了编码调用:

$token = JWT::encode($payload, $key, 'RS256', 'key_id_goes_here');

这导致了一个稍微不同的错误:身份验证标头中的无效声明“孩子”。,表明我在正确的轨道上…但不完全在那里。直接使用JWT令牌会产生完全相同的结果。知道我做错了什么吗?电子邮件、私钥和密钥id都直接来自我创建服务号时提供的json凭据文件。

我看了几十页的留档和帖子,以下是最有帮助的:

  • 使用JWT进行服务器身份验证(Firebase文档)
  • 使用自定义令牌向管理员FBDB发出REST请求
  • 是否仍然可以在Firebase 3中对令牌进行服务器端验证?

交叉发布到Firebase Google群组。


共2个答案

匿名用户

当使用服务号进行身份验证时,您可以指定一个auth_variable_override查询参数,该参数将成为安全规则中的auth变量。它应该是一个正确转义的JSON对象。例如,要执行{"uid": 123},您需要添加:

?auth_variable_override=%7B%22uid%22%3A%22123%22%7D

直到您的请求结束URL。

匿名用户

最终,我最终使用的解决方案是切换PHP库。我最初放弃了这个库,因为它正在转向仅支持PHP7,我还没有准备好迁移到它,但是当前版本(1.1)运行良好:

use Kreait\Firebase\Configuration;
use Kreait\Firebase\Firebase;

$clientId = '1234567890';
$email = 'account@email.com';
$key = 'private_key_goes_here';
$url = 'https://example.firebaseio.com';

$fbConfig = new Configuration();
$fbConfig->setAuthConfigFile([
    'type' => 'service_account',
    'client_id' => $clientId,
    'client_email' => $email,
    'private_key' => $key,
]);

$fb = new Firebase($url, $fbConfig);
$value = $fb->get('test/hello');
# $value now stores "world"