如何将 Firebase 数据库锁定到特定(电子邮件)域中的任何用户?

问题描述 投票:0回答:7

我有一个使用 Firebase 数据库的小型个人 Firebase Web 应用程序。我想保护(锁定)这个应用程序给来自单个特定域的任何用户。我想通过 Google 进行身份验证。我不清楚如何配置规则以表示“只有来自单个特定域(例如

@foobar.com
)的用户可以读取和写入此数据库”。

(我看到的部分问题是:很难用足够的信息引导数据库来使这个用例发挥作用。我需要在身份验证时知道用户的电子邮件,但是

auth
对象不包含电子邮件。这似乎是一个先有鸡还是先有蛋的问题,因为我需要编写引用数据库中数据的 Firebase 规则,但该数据还不存在,因为我的用户无法写入数据库。)

如果

auth
有电子邮件,那么我可以轻松编写规则。

提前致谢!

firebase firebase-security firebase-realtime-database firebase-authentication
7个回答
60
投票

如果您使用新的 Firebase,现在这是可能的,因为

email
在安全规则中可用。

在安全规则中,您可以访问电子邮件地址以及是否经过验证,这使得一些很棒的用例成为可能。例如,通过这些规则,只有经过身份验证、验证的 Gmail 用户才能编写他们的个人资料:

{
  "rules": {
    ".read": "auth != null",
    "gmailUsers": {
      "$uid": {
        ".write": "auth.token.email_verified == true && 
                   auth.token.email.matches(/.*@gmail.com$/)"
      }
    }
  }
}

您可以在项目的 Firebase 数据库控制台中输入这些规则。


3
投票

这是与我的数据库配合良好的代码,我设置了规则,只有我公司的电子邮件可以读取和写入我的 firebase 数据库的数据。

{
  "rules": {
    ".read": "auth.token.email.matches(/.*@yourcompany.com$/)",


        ".write": "auth.token.email.matches(/.*@yourcompany.com$/)"
      }
    }

3
投票

对我有用的代码。

export class AuthenticationService {

    user: Observable<firebase.User>;

    constructor(public afAuth: AngularFireAuth) {
        this.user = afAuth.authState;
    }

    login(){
        var provider = new firebase.auth.GoogleAuthProvider();
        provider.setCustomParameters({'hd': '<your domain>'});
        this.afAuth.auth.signInWithPopup(provider)
        .then(response => {
            let token = response.credential.accessToken;
            //Your code. Token is now available.
        })
    }
}

2
投票

警告:不要相信这个答案。只是来这里讨论。

tldr:如果不运行自己的服务器,我认为这是不可能的。

这是我迄今为止的尝试:

{
  "rules": {
    ".read": "auth.provider === 'google' && root.child('users').child(auth.uid).child('email').val().endsWith('@foobar.com')",
    ".write": "auth.provider === 'google' && root.child('users').child(auth.uid).child('email').val().endsWith('@foobar.com')",
    "users": {
      "$user_id": {
        ".write": "auth.provider === 'google' && $user_id === auth.uid && newData.child('email').val().endsWith('@foobar.com')"
      }
    }
  }
}

我相信上面说的“只有通过 Google 身份验证的人才允许创建新用户,并尝试自己写入数据库节点 (

$user_id === auth.uid
) 并且他们的电子邮件以 foobar.com 结尾”。

但是,有人指出了一个问题:任何 Web 客户端都可以在消息发送到 Firebase 之前轻松更改其电子邮件(使用开发控制台)。因此,当用户条目的数据存储到 Firebase 中时,我们不能信任该数据。

我认为我们唯一真正可以信任的是规则中的

auth
对象。该
auth
对象由 Firebase 的后端填充。而且,不幸的是,
auth
对象不包含电子邮件地址。

为了记录,我以这种方式插入我的用户:

function authDataCallback(authData) {
  if (authData) {
    console.log("User " + authData.uid + " is logged in with " + authData.provider + " and has displayName " + authData.google.displayName);
    // save the user's profile into the database so we can list users,
    // use them in Security and Firebase Rules, and show profiles
    ref.child("users").child(authData.uid).set({
      provider: authData.provider,
      name: getName(authData),
      email: authData.google.email
    });

正如您可能想象的那样,坚定的用户可以在此处覆盖

email
的值(例如,通过使用 DevTools)。


2
投票

这应该适用于任何寻求 Cloud Firestore 选项的人,其灵感来自于 Frank van Puffelen 的答案。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
    // Allows all users to access data if they're signed into the app with an email of the domain "company.com"
      allow read, write: if request.auth.uid != null && request.auth.token.email.matches(".*@company.com$");
    }
  }
}

0
投票

对于那些真正不想让未经验证的帐户登录的人来说。也许很肮脏,但非常有效。

这是我的解决方法(Angular 应用程序):

this.userService.login(this.email.value, this.password.value).then(data => {
  if (data.user.emailVerified === true) {
    //user is allowed
  } else {
    //user not allowed, log them out immediatly
    this.userService.logout();
  }
}).catch(error => console.log(error));

0
投票

您可以使用阻止功能扩展 Firebase 身份验证

例如:

const identity_1 = require("firebase-functions/v2/identity");
const logger = require("firebase-functions/logger");

/**
 * Block account creation for all but @foobar.com
 */
exports.blocking = (0, identity_1.beforeUserCreated)((event) => {
    const user = event.data;
    if (!user.email || !user.email.endsWith("@foobar.com")) {
        logger.info("ACCOUNT CREATION BLOCKED", { email: user.email });
        throw new identity_1.HttpsError("invalid-argument", "Unauthorized email");
    }
    else {
        logger.info("ACCOUNT CREATED", { email: user.email });
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.