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

如何将Firebase数据库锁定到特定(电子邮件)域的任何用户?,firebase,firebase-security,firebase-realtime-database,firebase-authentication,Firebase,Firebase Security,Firebase Realtime Database,Firebase Authentication,我有一个使用Firebase数据库的小型个人Firebase Web应用程序。我想保护(锁定)来自单个特定域的任何用户的此应用程序。我想通过谷歌认证。我不清楚如何将规则配置为“只有来自单个特定域(比如@foobar.com)的用户才能读写此数据库” (我看到的部分问题是:很难用足够的信息来引导数据库,以使此用例正常工作。我需要在身份验证时了解用户的电子邮件,但auth对象不包含电子邮件。这似乎是个鸡蛋问题,因为我需要编写引用数据库中数据的Firebase规则,但ta还不存在,因为我的用户无法写入

我有一个使用Firebase数据库的小型个人Firebase Web应用程序。我想保护(锁定)来自单个特定域的任何用户的此应用程序。我想通过谷歌认证。我不清楚如何将规则配置为“只有来自单个特定域(比如
@foobar.com
)的用户才能读写此数据库”

(我看到的部分问题是:很难用足够的信息来引导数据库,以使此用例正常工作。我需要在身份验证时了解用户的电子邮件,但
auth
对象不包含电子邮件。这似乎是个鸡蛋问题,因为我需要编写引用数据库中数据的Firebase规则,但ta还不存在,因为我的用户无法写入数据库。)

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

提前感谢!

警告:不要相信这个答案。请在此讨论。 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')"
      }
    }
  }
}
我相信上面说的“只有当人们通过谷歌认证,试图为自己写入数据库节点(
$user\u 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
    });

正如您可以想象的那样,一个有决心的用户可以在此处覆盖
电子邮件的值(例如,通过使用DevTools)。

如果您使用新的Firebase,这现在是可能的,因为
电子邮件在安全规则中可用

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

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

您可以在项目的中输入这些规则。

这里的代码可以很好地使用我的数据库,我已经设置了只有我的公司电子邮件才能读取和写入我的firebase数据库的数据的规则

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


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

对我有用的代码

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.
        })
    }
}
导出类身份验证服务{
用户:可观察;
构造函数(公共afAuth:AngularFireAuth){
this.user=afAuth.authState;
}
登录(){
var provider=new firebase.auth.GoogleAuthProvider();
setCustomParameters({'hd':''});
此.afAuth.auth.signInWithPopup(提供程序)
。然后(响应=>{
让令牌=response.credential.accessToken;
//您的code.Token现在可用。
})
}
}

适用于不想让未经验证的帐户登录的任何人。可能是肮脏的,但非常有效

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


这应该适用于任何寻求云Firestore选项的人,灵感来自于的答案

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$");
    }
  }
}

问:当你说从单个域锁定时,是指锁定到单个提供商,比如谷歌,还是字面意思是只允许myDomain的用户访问你的Firebase,即。test@myDomain通过密码进行身份验证是可以的,但是thing@anotherDomain通过谷歌认证是不允许的。我是说,“来自@foobar.com的任何人,经谷歌验证/认证,都可以读写数据库"你真的需要一个规则吗?在某些时候,用户必须首先输入他们的电子邮件地址才能登录或创建他们的帐户,所以你不能在输入时对其进行解析并拒绝任何没有@foobar.com作为域的邮件吗?不幸的是,一个有决心的用户可以使用浏览器的DevTools插入任何email他们想要。电子邮件地址不是来自客户端的可信数据。问题是,我不信任web浏览器,因为开发工具很容易允许恶意用户伪造oauth提供程序返回的数据。正如您确实发现的:
。write
规则可以控制谁可以写入某个位置,而
规则可以验证e他们写的是一个有效的电子邮件地址。但无法在安全规则中验证它是否确实是该用户的电子邮件地址。为此,您需要运行一些可信代码(通常在服务器上)将此验证的电子邮件地址写入(否则为只读)数据库中的位置。保存
auth.token
中可用的文档。如果看到从数据库的根目录中提取
@gmail.com
,例如
my_database/acceptable_domains/
的示例会很酷,例如,如果他们只想打开少数emai的应用程序如授权学校和企业,有没有其他不需要硬编码的域名,比如“Gmail用户”?如何限制只有特定域用户才能注册的gmail域。例如,我的公司abc使用gmail邮件服务,因此任何用户
good@abc.com
可以注册,我正在使用android版的gmail OAuth firestore。firestore有类似的功能吗?这很有效!
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$");
    }
  }
}