Firebase admin sdk:用于授权的 idToken 或自定义令牌验证

Posted

技术标签:

【中文标题】Firebase admin sdk:用于授权的 idToken 或自定义令牌验证【英文标题】:Firebase admin sdk: idToken OR custom token verification for authorization 【发布时间】:2018-10-02 01:19:35 【问题描述】:

我在登录时在后端服务器上创建了一个自定义令牌,下面是代码:

UserSchema.methods.generateAuthToken = function() 
 var user = this;
 var access = "auth";

 return firebaseAdmin.default
  .auth()
  .createCustomToken(user._id.toHexString())
  .then(function(token) 
    user.tokens = user.tokens.concat([ access, token ]);
    return user.save().then(() => 
      return token;
    );
  );
;

并将此令牌存储在 mongodb 中,并通过名为“x-auth”的标头将其发送回客户端,然后将其存储在 cookie 中。

在客户端,使用此令牌登录如下:

axios(
  url: "/api/users/login",
  method: "POST",
  data: 
    email: data.email,
    password: data.password
  
).then(res => 
  Cookies.set("x-auth", res.headers["x-auth"],  expires: 7 );
  return firebase
    .auth()
    .signInWithCustomToken(res.headers["x-auth"])
    .then(response => 
      console.log("CA", response);
      response
        .getIdToken()
        .then(idToken => 
          Cookies.set("idToken", idToken,  expires: 7 );
        )
        .catch(e => );
      dispatch(
        login(
          token: Cookies.get("x-auth")
        )
      );
    );
);

现在为了调用 api 来获取所有用户,我将这些令牌、自定义令牌和 idToken 发送回服务器:

const authenticate = (req, res, next) => 
const token = req.header("x-auth");
const idToken = req.header("idToken");
User.findByToken(token, idToken)
.then(user => 
  if (!user) 
    return Promise.reject(
      message: "no user found with the associated token!"
    );
  
  req.user = user;
  req.token = token;
  next();
)
.catch(e => 
  res.status(401).send(setErrorMessage(e.message));
);
;

findByToken 如下:

UserSchema.statics.findByToken = function(token, idToken) 
var User = this;
return firebaseAdmin.default
.auth()
.verifyIdToken(idToken)
.then(function(decodedToken) 
  var uid = decodedToken.uid;
  return User.findOne(
    _id: uid,
    "tokens.access": "auth",
    "tokens.token": token
  );
)
.catch(function(e) 
  return Promise.reject(e);
);
;

为什么我必须发送这两个令牌进行授权,这里的概念有什么问题。

https://firebase.google.com/docs/auth/admin/verify-id-tokens

警告:Firebase Admin SDK 中包含的 ID 令牌验证方法旨在验证来自客户端 SDK 的 ID 令牌,而不是您使用 Admin SDK 创建的自定义令牌。有关详细信息,请参阅身份验证令牌。

请澄清我是否可以验证自定义令牌而不是 idToken 来检索 userId 并将其与 DB 匹配,而不是出于一个目的使用不同的令牌,或者我在这里做错了,自定义令牌不应该存储在 DB 中,还有其他一些方法。

现在,当我尝试获取所有用户时,它说:

Firebase ID 令牌已过期。从您的客户端应用程序获取新令牌并重试(auth/id-token-expired)。有关如何检索 ID 令牌的详细信息,请参阅 https://firebase.google.com/docs/auth/admin/verify-id-tokens。

【问题讨论】:

【参考方案1】:

使用令牌时,您需要区分每个令牌及其用途,并且每个令牌都有相关属性。

Custom Tokens:这些令牌将在服务器中生成(正如您所做的那样),并在客户端用于对客户端进行身份验证。这些令牌在一小时后过期。

会话 ID 令牌:(我称之为“会话 ID 令牌”只是为了区分它)当客户端与任何身份验证提供程序进行身份验证时,SDK 将交换用于会话的 ID 令牌的信息。这同样适用于自定义令牌,其中 SDK 将自定义令牌交换为 ID 令牌。 ID 令牌也是短暂的,将在一小时后过期。在获取 ID Token 时,SDK 还会收到一个刷新 Token,用于refreshing 会话 ID Token。 ID 令牌用于向 Firebase 发出经过身份验证的请求。

用于验证的 ID 令牌:要获取此令牌,您需要调用函数“getIDToken”(用于 Web)。此函数将返回一个 ID 令牌,该 ID 令牌只能用于验证来自客户端到您的服务器的请求。与其他令牌类似,这个令牌在一小时后过期。调用 getIDToken 时,如果当前过期,该函数将请求一个新的。

要验证 ID 令牌,您必须使用提到的令牌。如果您尝试使用会话 ID 令牌或自定义令牌,您将收到错误消息。如果您尝试使用过期的 ID 令牌,这同样适用。

所有刷新 ID Token 的调用和任务都由 SDK 在后台处理。

存储这些令牌不是一个好习惯,因为它们将在一小时后过期,最好调用适当的函数来获取最新令牌并传递正确的 ID 令牌以进行验证。

最后,您可以在这些链接中找到用于生成 custom token 和 ID Token 以进行验证的属性。

【讨论】:

我理解了以下内容,来自后端的自定义令牌用于登录到前端,前端将生成 idToken 并可用于客户端和服务器之间的进一步通信,并且每次传递令牌,我应该从 getIDToken() 中获取它,它会自动提供活动令牌,或者如果前一个令牌过期,它将生成新令牌,并且该令牌将包含 user_id,然后服务器可以使用它来允许访问并且有无需像我现在正在做的那样在 db 中存储自定义令牌并在每个请求上匹配它。对吗? 还有一点,像 Loopback.js 这样的框架,将所有访问令牌存储在一个单独的集合中,为什么他们必须首先存储它。我也在做的事情。有什么想法吗? 如果我的回答对你有帮助,请考虑选择它作为解决方案。 我们需要将令牌存储在数据库中,以便我们可以通过删除令牌来使登录无效。因此,在我的情况下,即使用 firebase,如果我没有将令牌存储在 DB 中,我将如何实现相同的功能,即使登录会话无效? @Vipul 您可以通过调用revokeRefreshTokens(uid) 使令牌无效。然后进行验证,请致电verifyIdToken(idToken, true)。第二个参数,称为“checkRevoked”,会额外检查令牌是否已被撤销。 (这是到 FB 服务器的额外网络往返,但据我判断,似乎最好几乎每次都这样做。)

以上是关于Firebase admin sdk:用于授权的 idToken 或自定义令牌验证的主要内容,如果未能解决你的问题,请参考以下文章

FireBase 消息无法在 OSGI 包中加载 admin_sdk.properties

Firebase - 使用 firebase admin sdk 跨子域共享身份验证

无法获取使用Admin SDK Firebase的用户列表

Firebase Admin SDK、FCM 云消息传递

Firebase Cloud Messaging:Firebase Admin SDK 中的设备组发送支持

如何从 Admin SDK 创建 Firebase 动态链接