通过简单的 HttpCall (Postman) 获取 Firebase Bearer 令牌

2024-02-12

我目前面临以下情况。

通过 google API 端点通过 HttpCall 发送 Firebase 消息:

https://fcm.googleapis.com/v1/projects/projectName/messages:send

在这里,我们必须将 OAuth2.0 与有效的 Bearer Token 一起使用,如本问题中讨论的:

我应该使用什么承载令牌进行 Firebase 云消息传递测试? https://stackoverflow.com/questions/50399170/what-bearer-token-should-i-be-using-for-firebase-cloud-messaging-testing

遵循这些步骤后,我能够通过 google API 发送 Firebase 消息。

现在我想通过 HttpCall 获取不记名令牌,而无需使用 Playground 执行手动步骤https://developers.google.com/oauthplayground https://developers.google.com/oauthplayground.

我找不到任何有关如何通过简单的 HttpCall“交换令牌的授权代码”的文档。我无法实现任何代码,因为我想在“云流”内发送 Firebase 消息,因此无法加载任何外部 DLL(例如 Firebase Admin Dll,它将实现此功能)。

任何帮助表示赞赏


下面的代码是一个邮递员预请求脚本 https://learning.postman.com/docs/writing-scripts/pre-request-scripts/安装在您的 API 集合上,其中包含您正在测试的路由。其目的是将静态凭据(例如电子邮件密码组合或服务帐户密钥)转换为用于 API 调用的访问令牌。

模拟用户

要使用它代表用户进行测试,您可以添加X-Auth-Token-Type: user请求上的标头(由下面的脚本使用和删除),您需要设置以下环境变量 https://learning.postman.com/docs/sending-requests/managing-environments/#editing-environment-variables:

Name Value
firebase_apiKey The Firebase API Key for a web application https://console.firebase.google.com/project/_/settings/general
firebase_test_user An email for an account used for testing
firebase_test_password A password for an account used for testing

模拟服务帐户(谨慎使用!)

要代表服务帐户使用它进行测试,您需要添加X-Auth-Token-Type: admin请求上的标头(由下面的脚本使用和删除),您需要设置以下环境变量 https://learning.postman.com/docs/sending-requests/managing-environments/#editing-environment-variables:

Name Value
firebase_privateKey The value of private_key in a Service Account Key https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk
Important: For security do not set the "initial value" for this variable!
firebase_scope (optional) A space-delimited list of scopes to authenticate for.
Note: If omitted, the default Admin SDK scopes https://github.com/firebase/firebase-admin-node/blob/2feece31422c62ba9f57751221c8e459abf931c1/src/credential/credential-internal.ts#L111-L117 are used

预请求脚本

const { Header, Response, HeaderList } = require('postman-collection');

/**
 * Information about the current Firebase user
 * @typedef {Object} UserInfo
 * @property {String} accessToken - The Firebase ID token for this user
 * @property {String | undefined} displayName - Display name of the user, if available
 * @property {Number} expiresAt - When this token expires as a unix timestamp
 * @property {String | undefined} email - Email associated with the user, if available
 * @property {String} refreshToken - Refresh token for this user's ID token
 * @property {String} uid - User ID for this user
 */

/**
 * Loads a third-party JavaScript module from a CDN (e.g. unpkg, jsDelivr)
 * @param {[String, String, String]} moduleTuple - Array containing the module's ID, its source URL and an optional SHA256 signature
 * @param {Object | (err: any, exports: any) => any} exportsRefOrCallback - Object reference to use as `exports` for the module or a result handler callback
 * @param {(err: any, exports: any) => any} callback - result handler callback
 */
function loadModule(moduleTuple, exportsRefOrCallback, callback = undefined) {
    const exports = arguments.length == 2 ? {} : exportsRefOrCallback;
    callback = arguments.length == 2 ? exportsRefOrCallback : callback;
    const [id, src, signature] = moduleTuple;
   
    if (pm.environment.has("jslibcache_" + id)) {
        const script = pm.environment.get("jslibcache_" + id);

        if (signature && signature === CryptoJS.SHA256(script).toString()) {
            console.log("Using cached copy of " + src);
            try {
              eval(script);
              return callback(null, exports);
            } catch {}
        }
    }

    pm.sendRequest(src, (err, response) => {
        try {
            if (err || response.code !== 200) {
                pm.expect.fail('Could not load external library');
            }

            const script = response.text();
            signature && pm.expect(CryptoJS.SHA256(script).toString(), 'External library (' + id + ') has a bad SHA256 signature').to.equal(signature);
            pm.environment.set("jslibcache_" + id, script);
            eval(script);

            callback(null, exports);
        } catch (err) {
            callback(err, null);
        }
    });
}

/**
 * Signs in a test user using an email and password combination
 * 
 * @param {String} email email of the account to sign in with
 * @param {String} password email of the account to sign in with
 * @param {(error: any, response: Response) => any} callback request result handler
 */
function signInWithEmailAndPassword(email, password, callback) {
    pm.sendRequest({
        url: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=" + encodeURIComponent(pm.environment.get("firebase_apiKey")),
        body: JSON.stringify({ email, password, "returnSecureToken": true }),
        headers: new HeaderList({}, [new Header("application/json", "Content-Type")]),
        method: "POST"
    }, callback);
}

/**
 * Builds an Admin SDK compatible JWT using a Service Account key
 * 
 * Required Environment Variables:
 *  - `firebase_privateKey` - the private key from inside a service account key JSON file
 * 
 * Environment Variables:
 *  - `firebase_scope` - scopes used for the access token, space delimited
 * 
 * @param {Boolean | (error: any, idToken: String) => any} callbackOrForceRefresh token result handler or `true` to force using a fresh user token
 * @param {(error: any, idToken: String) => any} [callback] token result handler
 */
function getAdminToken(callbackOrForceRefresh, callback) {
    let forceRefresh = Boolean(callbackOrForceRefresh);
    if (arguments.length === 1) {
        callback = callbackOrForceRefresh;
        forceRefresh = callbackOrForceRefresh = false;
    }

    loadModule(
        ["jsrsasign", "https://unpkg.com/[email protected] /cdn-cgi/l/email-protection/lib/jsrsasign.js", "39b7a00e9eed7d20b2e60fff0775697ff43160e02e5276868ae8780295598fd3"],
        (loadErr, { KJUR }) => {
            if (loadErr) return callback(loadErr, null);
            
            const exp = pm.environment.get("currentAdmin.exp");
            const nowSecs = Math.floor(Date.now() / 1000);

            if (exp && exp > nowSecs && forceRefresh === false) {
                return callback(null, pm.environment.get("currentAdmin.jwt"));
            }

            try {
                if (!pm.environment.has('firebase_privateKey')) {
                    pm.expect.fail('Missing required environment variable "firebase_privateKey".');
                }

                // use specified scopes, or fallback to Admin SDK defaults
                const scope = pm.environment.get('firebase_scope') || 'https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/firebase.database https://www.googleapis.com/auth/firebase.messaging https://www.googleapis.com/auth/identitytoolkit https://www.googleapis.com/auth/userinfo.email';
                const privateKey = String(pm.environment.get('firebase_privateKey')).replace("\\n", "\n");

                const header = {"alg" : "RS256", "typ" : "JWT"};
                
                const claimSet =
                {
                    "iss": "https://securetoken.google.com/" + pm.environment.get("firebase_projectId"),
                    "scope": scope,
                    "aud":"https://accounts.google.com/o/oauth2/auth",
                    "exp": nowSecs + 3600, // now + 1 hour
                    "iat": nowSecs
                }

                const jwt = KJUR.jws.JWS.sign(null, header, claimSet, privateKey);
                
                // comment these lines out to disable caching
                pm.environment.set("currentAdmin.jwt", jwt);
                pm.environment.set("currentAdmin.exp", claimSet.exp);

                callback(null, jwt);
            } catch (err) {
                callback(err, null);
            }
        }
    );
}

/**
 * Builds a User ID Token using an email-password combo
 * 
 * Required Environment Variables:
 *  - `firebase_apiKey` - the Firebase API key for a web application
 *  - `firebase_test_user` - an email for a test user
 *  - `firebase_test_password` - the password for the test user
 * 
 * @param {Boolean | (error: any, idToken: String) => any} callbackOrForceRefresh token result handler or `true` to force using a fresh user token
 * @param {(error: any, idToken: String) => any} [callback] token result handler
 */
function getIdToken(callbackOrForceRefresh, callback) {
    let forceRefresh = Boolean(callbackOrForceRefresh);
    if (arguments.length === 1) {
        callback = callbackOrForceRefresh;
        forceRefresh = callbackOrForceRefresh = false;
    }

    if (pm.environment.has("currentUser") && forceRefresh === false) {
        /** @type UserInfo */
        const currentUser = JSON.parse(pm.environment.has("currentUser"));
        if (currentUser.expiresAt > Date.now()) { // has token expired?
            return callback(null, currentUser.accessToken);
        }
    }

    try {
        if (!pm.environment.has('firebase_apiKey')) {
            pm.expect.fail('Missing required environment variable "firebase_apiKey".');
        }
        if (!pm.environment.has('firebase_test_user')) {
            pm.expect.fail('Missing required environment variable "firebase_test_user".');
        }
        if (!pm.environment.has('firebase_test_password')) {
            pm.expect.fail('Missing required environment variable "firebase_test_password".');
        }
    } catch (err) {
        return callback(err, null);
    }

    signInWithEmailAndPassword(pm.environment.get("firebase_test_user"), pm.environment.get("firebase_test_password"), (err, response) => {
        if (err || response.code !== 200) {
            pm.expect.fail('Could not sign in user: ' + response.json().error.message);
        }

        /** @type String */
        let accessToken;

        try {
            const { idToken, refreshToken, email, displayName, localId: uid, expiresIn } = response.json();
            accessToken = idToken;
            const expiresAt = Date.now() + Number(expiresIn);

            // comment these lines out to disable caching
            pm.environment.set("currentUser", JSON.stringify({ accessToken, refreshToken, email, displayName, uid, expiresAt }));
            // pm.environment.set("currentUser.accessToken", accessToken);
            // pm.environment.set("currentUser.refreshToken", refreshToken);
            // pm.environment.set("currentUser.email", email);
            // pm.environment.set("currentUser.displayName", displayName);
            // pm.environment.set("currentUser.uid", uid);
            // pm.environment.set("currentUser.expiresAt", expiresAt);

        } catch (err) {
            return callback(err, null);
        }

        callback(null, accessToken);
    });
}

const tokenTypeHeader = pm.request.headers.one("X-Auth-Token-Type");
pm.request.removeHeader("X-Auth-Token-Type");

switch (tokenTypeHeader && tokenTypeHeader.value.toLowerCase()) {
    case "admin":
        getAdminToken(false, (err, token) => { 
            if (err || !token) pm.expect.fail("failed to get admin SDK token for request: " + err.message);
            pm.request.addHeader(new Header("Bearer " + token, "Authorization"));
        });
        break;
    case "user":
        getIdToken(false, (err, idToken) => {
            if (err || !idToken) pm.expect.fail("failed to get user ID token for request: " + err.message);
            pm.request.addHeader(new Header("Bearer " + idToken, "Authorization"));
        });
        break;
    default:
        break; // no auth, do nothing
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过简单的 HttpCall (Postman) 获取 Firebase Bearer 令牌 的相关文章

  • 如何将 Cloud Firestore 数据库集合下载到 JSON 或 CSV 文件中?

    好的 事情是这样的 我已经在 Flutter Firebase 项目上工作了一段时间 现在我的客户想知道是否有机会从 Cloud Firestore 数据库的某个集合中获取 CSV o JSON 文件 以便稍后使用由Power Bi或其他一
  • 如何使用 firebase 托管托管 sveltekit 应用程序?

    我正在尝试将 sveltekit 应用程序部署到 firebase 带有 sveltekit 的 bigginner 我以为我们要构建应用程序并获取我们的 index html 文件 但 sveltkit 的情况并非如此 我正在使用 sve
  • 在 firebase 函数 onFinalize 中获取用于 firebase 存储的 uid

    我使用 firebase JS sdk 将音频文件上传到 firebase storage 发生这种情况时 我需要根据进行上传的经过身份验证的用户来处理它 我将其上传到其他地方进行处理 这意味着我需要在通过存储规则验证 uid 后才能访问该
  • Firestore 中的多租户

    关于基于子集合值查询数据的实际限制 在 Firestore 中管理多租户的建议方法是什么 我希望能够检索和限制对与用户所属实体 公司相关的数据的访问 数据结构示例 companies companyId users companies co
  • 如何在 Firebase 控制台中使用 Apple 新的 APN .p8 证书

    随着最近 Apple 开发者帐户的升级 我面临着一个困难 在尝试创建推送通知证书时 它为我提供了 p8 证书 而不是可以导出到 p12 的 APNs 证书 Firebase 控制台仅接受 p12 证书 那么我如何从这些新的 p8 证书中获取
  • 是否可以使用 Firebase 安排推送通知? [复制]

    这个问题在这里已经有答案了 我已经阅读了我能找到的所有文档 但仍然不知道这是否可行 如果我是用户 我可以安排特定时间的推送通知吗 Example 1 我是用户并打开应用程序 2 我允许通知并转到 pickerView 或其他任何内容 并设置
  • Firebase 身份验证问题 - 通过电子邮件地址检查用户是否存在

    我在 Firebase 上创建了一个帐户 它有效 但现在我想阻止人们使用已存在的电子邮件地址创建帐户 这是代码 DatabaseManager shared userExists with email completion weak sel
  • 为 Node.js 客户端应用程序保留 Firebase 用户

    我正在使用 Firebase 构建 Node js 命令行界面 CLI 用于与后端进行身份验证 我想避免让用户每次运行命令时都输入密码 相反 我想实现一个 登录 流程 将凭证保留到文件系统 该凭证可用于后续的无密码身份验证 直到用户 注销
  • Firestore - 从文档中获取特定字段

    我需要的 我想在 Firestore 中保存文章或注释及其各自的字段 Title 内容 文本或段落 创建日期 所有者 与其他人分享该文章 人和谁可以编辑它们 例如 https firebase google com docs firesto
  • 有没有办法在 Firebase 中等待查询完成?

    我正在使用 TableView 在 Viewcontroller 中的 iOS 应用程序中进行查询 我想确保在继续加载 TableView 之前我的查询已经返回 有没有办法保证查询已经完成 None
  • BigQuery 未显示链接的 Firebase Analytics 事件日志的任何数据集

    我将我的帐户链接到 Big Query 但 Firebase Analytics 事件不会自动加载到 BigQuery 中 显示 未找到数据集 警告 我的工作进度附在下面 请查收 I have getting firebase Analyt
  • 谷歌云功能发送重复通知

    我有一个发送主题通知的 gcf 我从管理 Android 应用程序触发该功能 一切都按预期工作 但突然该函数发送通知两次 有时三次 谷歌云上的函数日志显示该函数已发送一条通知 它只打印一行 定制发送成功 但 Android 应用程序会收到多
  • Firebase - 有没有办法查看有多少人安装了该应用程序?

    Parse 支持安装功能 我不确定 firebase 是否也支持 但在 Google 中挖掘了几个小时后 我无法找到有关如何在 Firebase 中查看 计算用户安装的重要信息 有没有办法计算 Firebase 中的用户安装量 或者甚至还有
  • IOS 应用程序提交导出合规性:Firebase

    我准备将我的应用程序提交到应用程序商店 经过一些研究后 我似乎仍然无法在我的应用程序中找到有关 firebase 的任何信息 Firebase 是否可以豁免 我只用它来进行分析和 Admob 那么 Firebase 是否使用加密 如果使用
  • 如何将 Firestore 文档数据转换为类

    在 Firestore 中 有一些文档包含 名称 大陆 等字段及其字符串值 我在主 UI 代码中使用 FutureBuilder 并调用getData 功能 这是我的代码 class DatabaseService final locati
  • 12501 错误:Ionic 构建应用程序时使用什么密钥库

    我在用Ionic 2 with GooglePlus 身份验证 https ionicframework com docs v2 native google plus 一切都很完美iOS For Android我按如下方式构建我的应用程序
  • 缓存 firestore 中 get 的第一个实现

    我希望 firestore 每次都先从缓存中获取数据 根据 Firestore 文档 传递 缓存 或 服务器 选项必须启用相同的功能 下面的例子 db collection cities where capital true get cac
  • firebase createUser 无需登录[重复]

    这个问题在这里已经有答案了 我的管理员用户可以创建其他用户 但每次创建用户时 我的管理员用户都会注销 新用户会自动登录 有什么方法可以在不登录的情况下创建用户吗 None
  • 我在布局上看不到任何 FirebaseRecyclerAdapter 项目

    我试图将数据从 Firebase 数据库检索到我的布局 但我看不到任何项目FirebaseRecyclerAdapter在布局中 请帮忙 我按照一个教程展示了如何做到这一点 当我运行应用程序时 我没有看到任何项目 但我可以滚动 public
  • 如何设置Firestore安全规则? Resource.data:空值错误

    我需要一些帮助来使我的 Firestore 安全规则发挥作用 这些是我的 Firestore 规则 service cloud firestore match databases database documents match order

随机推荐