使用 php 设置 firebase v3 自定义身份验证

Posted

技术标签:

【中文标题】使用 php 设置 firebase v3 自定义身份验证【英文标题】:Setting up firebase v3 custom auth with php 【发布时间】:2016-10-14 13:29:32 【问题描述】:

我正在尝试按照这些准则使用来自谷歌的新 firebase sdk 设置自定义身份验证:https://firebase.google.com/docs/auth/server#use_a_jwt_library 在 samble 代码中它说:

从 JSON 密钥文件中获取您的服务帐户的电子邮件地址和私钥

不幸的是,我不知道从哪里获得这个 json 文件。如果我转到我的 firebase 控制台 (https://console.firebase.google.com/),我会设法下载一个 json 文件,但它不包含任何电子邮件地址和私钥。

通过进入“API Manager > Credentials”菜单,我设法在我的谷歌云平台控制台 (http://console.cloud.google.com) 中找到了一个包含电子邮件地址和私钥的 json 文件。令人惊讶的是,我的 firebase 应用程序在那里显示。我将电子邮件和密钥复制并粘贴到示例代码中,然后出现此错误:

警告:openssl_sign():提供的密钥参数无法强制转换为 /volume1/web/yeti/vendor/firebase/php-jwt/src/JWT.php 中的私钥,第 183 行致命错误:未捕获的异常“DomainException” ' 在 /volume1/web/yeti/vendor/firebase/php-jwt/src/JWT.php:185 中带有消息 'OpenSSL 无法签署数据' 堆栈跟踪:#0 /volume1/web/yeti/vendor/firebase/php -jwt/src/JWT.php(154): Firebase\JWT\JWT::sign('eyJ0eXAiOiJKV1Q...', NULL, 'RS256') #1 /volume1/web/yeti/jwt.php(21): Firebase\JWT\JWT::encode(Array, NULL, 'RS256') #2 /volume1/web/yeti/jwt.php(24): create_custom_token('1234', false) #3 main 在 /volume1 中抛出/web/yeti/vendor/firebase/php-jwt/src/JWT.php 在第 185 行

有人知道我做错了什么吗?

谢谢

【问题讨论】:

Firebase 项目“只是”一种特殊类型的 Google Cloud Platform 项目,因此您的 Firebase 项目确实应该显示在 Google Cloud Platform 控制台中。在创建服务帐户时,请参阅this link中的第一段 感谢您的回答。但仍然无法正常工作。做了链接中解释的事情。仍然得到同样的错误。 (警告:openssl_sign():提供的密钥参数不能被强制转换为私钥) 【参考方案1】:

发现我自己出了什么问题! 文档中的示例 php 代码有问题。而不是

return JWT::encode($payload, $private_key, "RS256");

使用

return JWT::encode($payload, $private_key, "HS256");

编辑: 实际上,只是来自 google firebase doc 的示例 php 代码完全有问题。它向 php-jwt 传递了一个空键。看起来他们今天更新了它并且运行良好:)

【讨论】:

很高兴听到您发现问题并感谢您的反馈!我将添加一条说明,我们需要更新文档。 这一行的示例php代码中还有一个语法错误:"claims" => array( "premium_account" => $is_premium_account ); ;应该删除 这个令牌绝对不会验证。 Google 仅使用 RS256 JWT。 看起来你是对的。现在我得到这个异常com.google.firebase.auth.FirebaseAuthInvalidCredentialsException:自定义令牌格式不正确。请查看文档。 实现时mAuth.signInWithCustomToken(result) .addOnCompleteListener(YetieActivity.this, new OnCompleteListener<AuthResult>() ...【参考方案2】:

您找到解决方案了吗?仍然遇到同样的问题!适用于 HS256,不适用于 RS256。是谷歌云的限制吗?


非常感谢! @dbburgess

问题:使用了错误的密钥和电子邮件。这些应在与 Firebase 项目对应的 Google Cloud 凭据部分中生成。

解决办法:

转到“console.cloud.google.com”。 选择相关的 Firebase 项目。 然后是“API 管理器”->“凭据”。 “创建凭据”->“服务帐户密钥”-> 选择 JSON。 创建的文件将包含所需的“private_key”和“client_email”。

填写值:

$service_account_email = "autogeneratedemail@developer.gserviceaccount.com"; $private_key = "-----开始私钥-----\nSoneVeryVeryLongKey=\n-----结束私钥-----\n"; $uid = 'UserToUseInFirebaseRules'; $is_premium_account = $uid;

您不需要更改“create_custom_token”函数中的任何内容,可能根据您的需要更改到期日期/时间。

然后调用函数:

create_custom_token($uid, $is_premium_account);

【讨论】:

create_custom_token 是什么函数? 取自文档。【参考方案3】:

这就是我正在做的事情,而且效果很好。您在claims 数组中提供的内容是安全规则中auth 上显示的内容。电子邮件和密钥来自您在create a service account 时获得的 json 文件(请参阅:开始之前部分)。

$userId = '1234';
$email = 'sample@email.com';
$key = 'giant_key_goes_here';

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

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

值得注意的是,键的格式有点棘手...您的键看起来像这样(只是一个示例键):

-----BEGIN PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END PRIVATE KEY-----

你可能需要做一些花哨的格式化,这基本上就是我所做的:

$key = "-----BEGIN PRIVATE KEY-----\nMIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp\nwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5\n1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh\n3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2\npIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX\nGukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il\nAkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF\nL0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k\nX6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl\nU9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ\n37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=\n-----END PRIVATE KEY-----\n";

请注意,换行符变成了\n,并且都被压缩到了一行。有多种方法可以完成它,但是...根据您遇到的错误,可能是这样的问题。

【讨论】:

你好@dbburgess你能帮助如何将私钥更改为单行字符串吗?谢谢【参考方案4】:

而不是

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

使用

define("FIREBASE_PRIVATE_KEY","giant_key_goes_here");
token = JWT::encode($payload, FIREBASE_PRIVATE_KEY, 'RS256');

【讨论】:

你能解释一下你的推理吗?这有什么不同? 我不是 php 专家,只分享我如何设法解决与 OP 类似的问题。【参考方案5】:

我遇到了同样的问题。阅读@Jean-Philippe 的答案后,我能够使用HS256 而不是RS256 生成令牌。但这会导致每次更改凭据后令牌都无效。

使用jwt.io 调试它,一切正常,但仍然从firebase.auth().signInWithCustomToken(token).catch(function (error) 获得无效令牌。

在 github 中搜索后,我找到了this issue。所以我在$private 中使用了双引号而不是单引号,并且它与RS256 一起使用。

require_once('../vendor/autoload.php');
use \Firebase\JWT\JWT;

$service_account_email = env('ACCOUNT_EMAIL');
$private_key = env('ACCOUNT_SECRET');

class generateToken

    public static function generateNewToken($mysqli, $userID, $email)
    
        global $service_account_email, $private_key;

        $name = '';
        $lastname = '';
        $hostOption = '';
        $now_seconds = time();

        $selectUserData = "SELECT username, lastname, hostOption FROM signup WHERE id = ? ";
        $stmt = $mysqli->prepare($selectUserData);
        $stmt->bind_param('i', $userID);
        $stmt->execute();
        $stmt->store_result();
        $stmt->bind_result($name, $lastname, $hostOption);
        $stmt->fetch();

        $payload = array(
            "iss" => $service_account_email,
            "sub" => $service_account_email,
            "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
            "iat" => $now_seconds,
            "exp" => $now_seconds + (60 * 60),  // Maximum expiration time is one hour
            "uid" => strval($userID),
            "claims" => array(
                "username" => $name,
                "lastname" => $lastname,
                "email" => $email,
                "hostOption" => $hostOption,
            )
        );

        return JWT::encode($payload, $private_key, 'RS256');
    

env.php:

$vars = [
    'ACCOUNT_EMAIL' => "admin@myproject.iam.gserviceaccount.com",
    'ACCOUNT_SECRET' => "-----BEGIN PRIVATE KEY-----\nVERYLONGKEY=\n-----END PRIVATE KEY-----\n"
];

foreach($vars as $key => $value)
    putenv("$key=$value");

lindelius commented on 7 Aug 2018 • 
The reason is because the key contains new-line characters (\n) which are incorrectly handled when used within single-quotes, i.e. they are treated as the characters "\n" rather than actual new lines.

【讨论】:

以上是关于使用 php 设置 firebase v3 自定义身份验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 php-jwt 库解码 firebase 自定义令牌时出现 openssl_verify() 错误

PHP Firebase 帮助 - 设置 JWT

为动态链接设置自定义路由,而不使用 Firebase 托管

对使用自定义子域设置 Firebase 动态链接所需的 A 记录的担忧

如何在没有 Firebase 和自定义后端的情况下使用 Flutter 设置推送通知

将新数据推送到firebase数据库时设置自定义数字键