You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PL/SQL生成FCM Token?Oracle APEX集成Firebase场景

在PL/SQL中生成Firebase Cloud Messaging访问令牌

完全可以实现,核心就是在PL/SQL里构造符合Google OAuth2要求的JWT并完成签名——和你贴的JS代码逻辑本质是一样的,都是用服务账号生成认证令牌。

核心逻辑拆解

Firebase用的访问令牌是标准JWT格式,分三部分:

  • Header:固定使用RS256算法,声明令牌类型为JWT
  • Payload:必须包含服务账号邮箱、固定受众地址https://oauth2.googleapis.com/token、令牌签发时间和过期时间(最长1小时)
  • Signature:用服务账号的RSA私钥对前两部分的Base64URL编码结果做RS256签名

具体实现步骤

1. 准备服务账号信息

从Firebase控制台下载的服务账号JSON文件中,提取两个关键字段:

  • client_email:服务账号的邮箱地址
  • private_key:RSA私钥,注意把JSON里的换行符替换成PL/SQL可识别的CHR(10)

2. PL/SQL代码实现

直接用Oracle自带的加密和编码包即可完成,无需额外依赖:

DECLARE
  -- 替换为你的服务账号信息
  l_client_email VARCHAR2(200) := 'your-service-account@your-project.iam.gserviceaccount.com';
  l_private_key VARCHAR2(4000) := '-----BEGIN PRIVATE KEY-----' || CHR(10) || 
                                  'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...' || CHR(10) || 
                                  '-----END PRIVATE KEY-----';
  
  -- JWT相关变量
  l_header VARCHAR2(200);
  l_payload VARCHAR2(4000);
  l_encoded_header VARCHAR2(4000);
  l_encoded_payload VARCHAR2(4000);
  l_signature_input VARCHAR2(4000);
  l_signature RAW(2000);
  l_encoded_signature VARCHAR2(4000);
  l_access_token VARCHAR2(4000);
  
  -- 计算Unix时间戳(单位:秒)
  l_issued_at NUMBER := FLOOR(SYSDATE - TO_DATE('1970-01-01', 'YYYY-MM-DD')) * 86400 + FLOOR(SYS_EXTRACT_UTC(SYSTIMESTAMP) - TIMESTAMP '1970-01-01 00:00:00');
  l_expires_at NUMBER := l_issued_at + 3600; -- 令牌有效期设为1小时
BEGIN
  -- 构造JWT Header
  l_header := '{"alg":"RS256","typ":"JWT"}';
  
  -- 构造JWT Payload,需指定Firebase Messaging的权限范围
  l_payload := '{"iss":"' || l_client_email || '",' ||
               '"scope":"https://www.googleapis.com/auth/firebase.messaging",' ||
               '"aud":"https://oauth2.googleapis.com/token",' ||
               '"iat":' || l_issued_at || ',' ||
               '"exp":' || l_expires_at || '}';
  
  -- 对Header和Payload做Base64URL编码(替换+为-、/为_,去除末尾的=)
  l_encoded_header := REPLACE(REPLACE(UTL_ENCODE.base64_encode(UTL_I18N.string_to_raw(l_header, 'AL32UTF8')), '+', '-'), '/', '_');
  l_encoded_header := RTRIM(l_encoded_header, '=');
  
  l_encoded_payload := REPLACE(REPLACE(UTL_ENCODE.base64_encode(UTL_I18N.string_to_raw(l_payload, 'AL32UTF8')), '+', '-'), '/', '_');
  l_encoded_payload := RTRIM(l_encoded_payload, '=');
  
  -- 拼接签名输入字符串
  l_signature_input := l_encoded_header || '.' || l_encoded_payload;
  
  -- 用私钥执行RS256签名(Oracle 12c及以上版本支持,低版本需用Java存储过程替代)
  l_signature := DBMS_CRYPTO.SIGN(
    src => UTL_I18N.string_to_raw(l_signature_input, 'AL32UTF8'),
    key => UTL_I18N.string_to_raw(l_private_key, 'AL32UTF8'),
    typ => DBMS_CRYPTO.SIGNATURE_RSA_SHA256
  );
  
  -- 对签名结果做Base64URL编码
  l_encoded_signature := REPLACE(REPLACE(UTL_ENCODE.base64_encode(l_signature), '+', '-'), '/', '_');
  l_encoded_signature := RTRIM(l_encoded_signature, '=');
  
  -- 拼接完整JWT即为访问令牌
  l_access_token := l_encoded_header || '.' || l_encoded_payload || '.' || l_encoded_signature;
  
  -- 输出令牌,可修改为返回值供APEX调用
  DBMS_OUTPUT.PUT_LINE('生成的访问令牌:' || l_access_token);
END;
/

3. 关键注意事项

  • Oracle版本限制:12c及以上版本的DBMS_CRYPTO才支持SIGNATURE_RSA_SHA256签名算法,低版本建议通过Java存储过程调用JJWT等第三方JWT库实现签名。
  • 私钥格式:必须将私钥中的换行符替换为CHR(10),否则会导致签名失败。
  • 权限配置:执行代码的数据库用户需要拥有DBMS_CRYPTO、UTL_ENCODE、UTL_I18N包的EXECUTE权限。
  • 令牌有效期:JWT令牌最长有效期为1小时,需在过期前重新生成。

令牌有效性验证

生成令牌后,可通过Google的令牌校验接口传入access_token参数,确认令牌是否有效。

内容的提问来源于stack exchange,提问作者Pav4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:00:14