通过“ createCustomToken”方法发出的CustomToken不起作用 方法1:使用公私钥对方法2:添加仅具有云功能的用户客户端云功能第三方API

我正在为我的应用程序使用Firebase身份验证,并使用它使用JWT令牌将用户身份验证到后端API。在API后端,我配置了JWT-secret,这是从以下URL中提取的非对称密钥:

https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com

一切正常。最近,我需要创建一个云函数,该函数还需要调用API后端。为此,我正在使用该功能来创建位于以下位置的自定义令牌:

https://firebase.google.com/docs/auth/admin/create-custom-tokens

这会创建具有正确自定义声明的令牌

          let additionalClaims = {
             'x-hasura-default-role': 'admin','x-hasura-allowed-roles': ['user','admin']
           }     

        admin.auth().createCustomToken(userId,additionalClaims).then(function (customToken) {
        console.log(customToken);

        response.end(JSON.stringify({
          token: customToken
        }))
      })
      .catch(function (error) {
       console.log('Error creating custom token:',error);
    });

但是,当我尝试对后端API使用它时,出现“ JWTInvalidSignature”错误。在我的云功能中,我指定了Firebase项目中的服务帐户,但似乎无济于事。当我查看已解码的两个令牌时,它们肯定会来自不同的服务。

CustomToken

     {
      "aud": 
       "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit","iat": 1573164629,"exp": 1573168229,"iss": "firebase-adminsdk-r2942@postgrest-b4c8c.iam.gserviceaccount.com","sub": "firebase-adminsdk-r2942@postgrest-b4c8c.iam.gserviceaccount.com","uid": "mikeuserid","claims": {
           "x-hasura-default-role": "admin","x-hasura-allowed-roles": [
           "user","admin"
        ]
       }
    }

FireBase Auth中的令牌

 {
      "role": "webuser","schema": "customer1","userid": "15","claims": {
      "x-hasura-default-role": "user","x-hasura-allowed-roles": [
      "user","admin"
  ],"x-hasura-user-id": "OS2T2rdkM5UlhfWLHEjNExZ71lq1","x-hasura-dbuserid": "15"
   },"iss": "https://securetoken.google.com/postgrest-b4c8c","aud": "postgrest-b4c8c","auth_time": 1573155319,"user_id": "OS2T2rdkM5UlhfWLHEjNExZ71lq1","sub": "OS2T2rdkM5UlhfWLHEjNExZ71lq1","email": "johnny1@gmail.com","email_verified": false,"firebase": {
    "identities": {
     "email": [
    "johnny1@gmail.com"
  ]
  },"sign_in_provider": "password"
  }
 }

如何获取此customToken以与已配置的现有JWT秘密密钥一起使用??

whs1234567890 回答:通过“ createCustomToken”方法发出的CustomToken不起作用 方法1:使用公私钥对方法2:添加仅具有云功能的用户客户端云功能第三方API

Firebase Authentication: Users in Firebase Projects: Auth tokens中所述,Firebase Auth和Admin SDK自定义令牌中的令牌不相同,彼此不兼容且验证方式不同。


澄清后编辑后的回复:

当您尝试将云函数实例标识为第三方API的授权调用方时,可以使用两种方法。

在以下两种方法中,每个示例中都将使用postToApi('/saveUserData',{ ... });来调用API。您可能还可以结合/支持两种服务器端方法。

方法1:使用公私钥对

对于此版本,我们使用JSON Web令牌来证明该调用来自Cloud Functions实例。在这种形式的代码中,'private.key'文件与您的函数一起部署,并且其公钥保存在第三方服务器上。如果您经常调用API,请考虑将“ private.key”文件缓存在内存中,而不是每次都读取它。

如果您想使该密钥无效,则必须重新部署所有使用该密钥的功能。或者,您可以修改fileRead()调用并将其存储在Firebase Storage(secure it中-不能读取,可以由backend-admin写入)。只需替换文件,即可定期刷新私钥。

  • 优点:仅一个远程请求
  • 缺点:更新密钥可能很棘手
const jwt = require('jsonwebtoken');
const rp = require('request-promise-native');
const functionsAdminId = 'cloud-functions-admin';

function getFunctionsAuthToken(jwtOptions) {
  jwtOptions = jwtOptions || {};
  return new Promise((resolve,reject) => {
    // 'private.key' is deployed with function
    fs.readFile('private.key','utf8',(err,keyData) => {
      if (err) { return reject({src: 'fs',err: err}); }

      jwt.sign('cloud-functions-admin',keyData,jwtOptions,token) => {
        if (err) { return reject({src: 'jwt',err: err}); }
        resolve(token);
      });
    });
  });
}

示例用法:

function postToApi(endpoint,body) {
  return getFunctionsAuthToken()
    .then((token) => {
      return rp({
          uri: `https://your-domain.here${endpoint}`,method: 'POST',headers: {
            Authorization: 'Bearer ' + token
          },body: body,json: true
        });
    });
}

如果在服务器上使用Express,则可以使用express-jwt来反序列化令牌。如果配置正确,req.user将是'cloud-functions-admin',用于来自您的Cloud Functions的请求。

const jwt = require('express-jwt');

app.use(jwt({secret: publicKey});

方法2:添加仅具有云功能的用户

一种替代方法是通过使用Firebase Auth避免使用公私钥。这将有可能会较慢地进行权衡。

  • 优点:无需密钥管理,易于验证服务器上的用户
  • 缺点:由于Firebase身份验证调用(1-2)而变慢
const admin = require('firebase-admin');
const rp = require('request-promise-native');
const firebase = require('firebase');
const functionsAdminId = 'cloud-functions-admin';

function getFunctionsAuthToken() {
  const fbAuth = firebase.auth();
  if (fbAuth.currentUser && fbAuth.currentUser.uid == uid) {
    // shortcut
    return fbAuth.currentUser.getIdToken(true)
      .catch((err) => {src: 'fb-token',err: err});
  }

  return admin.auth().createCustomToken(functionsAdminId)
      .then(function(customToken) {
        return fbAuth.signInWithCustomToken(token)
          .then(() => {
            return fbAuth.currentUser.getIdToken(false)
              .catch((err) => {src: 'fb-token',err: err});
          })
          .catch((err) => {src: 'fb-login',err: err});
      })
      .catch((err) => {src: 'admin-newtoken',err: err});
}

示例用法:

function postToApi(endpoint,json: true
        });
    });
}

在服务器上,您将使用以下检查:

// idToken comes from the received message
admin.auth().verifyIdToken(idToken)
  .then(function(decodedToken) {
    if (decodedToken.uid != 'cloud-functions-admin') {
      throw 'not authorized';
    }
  }).catch(function(error) {
    // Handle error
  });

或者如果使用Express,则可以将其附加到中间件。

app.use(function handleFirebaseTokens(req,res,next) {
  if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
    var token = req.headers.authorization.split(' ')[1];
    admin.auth().verifyIdToken(idToken)
      .then((decodedToken) => {
        req.user = decodedToken;
        next();
      },(err) => {
        //ignore bad tokens?
        next();
      });
  } else {
    next();
  }
});

// later on: req.user.uid === 'cloud-functions-admin'


原始回复:

如果您的客户端使用来自SDK的Firebase身份验证进行登录,而您的服务器使用Admin SDK,则可以通过本质上“通过包裹”来使用客户端在云功能上的ID令牌与服务器进行对话以验证用户

客户端

firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
  // Send token to your cloud function
  // ...
}).catch(function(error) {
  // Handle error
});

云功能

// idToken comes from the client app
admin.auth().verifyIdToken(idToken) // optional (best-practice to 'fail-fast')
  .then(function(decodedToken) {
    // do something before talking to your third-party API
    // e.g. get data from database/secret keys/etc.
    // Send original idToken to your third-party API with new request data
  }).catch(function(error) {
    // Handle error
  });

第三方API

// idToken comes from the client app
admin.auth().verifyIdToken(idToken)
  .then(function(decodedToken) {
    // do something with verified user
  }).catch(function(error) {
    // Handle error
  });
本文链接:https://www.f2er.com/3141264.html

大家都在问