如何将 Firebase 数据库锁定给来自特定(电子邮件)域的任何用户?
Posted
技术标签:
【中文标题】如何将 Firebase 数据库锁定给来自特定(电子邮件)域的任何用户?【英文标题】:How do I lock down Firebase Database to any user from a specific (email) domain? 【发布时间】:2016-08-24 21:51:33 【问题描述】:我有一个使用 Firebase 数据库的小型个人 Firebase 网络应用。我想将此应用程序保护(锁定)给来自单个特定域的任何用户。我想通过 Google 进行身份验证。我不清楚如何将规则配置为“只有来自单个特定域(例如 @foobar.com
)的用户才能读取和写入此数据库”。
(我看到的部分问题:很难用足够的信息引导数据库以使这个用例工作。我需要在身份验证时知道用户的电子邮件,但 auth
对象不包含电子邮件。这似乎是一个鸡蛋问题,因为我需要编写引用数据库中数据的 Firebase 规则,但该数据还不存在,因为我的用户无法写入数据库。)
如果auth
有邮箱,那我就可以轻松编写规则了。
提前致谢!
【问题讨论】:
问题:当您说从单个域锁定时,这是否意味着锁定到单个提供商,例如 google,或者它的字面意思是只允许来自 myDomain 的用户访问您的 Firebase,即 test@ myDomain 通过密码验证是可以的,但是 thing@anotherDomain 通过 google 验证是不允许的。 我的意思是,“来自@foobar.com 的任何人,经 Google 验证/认证,都可以读取和写入数据库” 你真的需要规则吗?在某些时候,用户必须输入他们的电子邮件地址才能登录或首先创建他们的帐户,所以你不能在输入时解析它并拒绝任何没有@foobar.com作为域? 不幸的是,坚定的用户可以使用他们浏览器的 DevTools 插入他们想要的任何电子邮件。电子邮件地址不是来自客户端的可信数据。 问题是,我不信任网络浏览器,因为开发工具很容易让恶意用户伪造 oauth 提供者返回的数据。 【参考方案1】:如果您使用的是新的 Firebase,现在可以这样做了,因为安全规则中提供了 email
。
在安全规则中,您可以访问电子邮件地址以及它是否经过验证,这使得一些很好的用例成为可能。例如,使用这些规则,只有经过身份验证和验证的 gmail 用户可以编写他们的个人资料:
"rules":
".read": "auth != null",
"gmailUsers":
"$uid":
".write": "auth.token.email_verified == true &&
auth.token.email.matches(/.*@gmail.com$/)"
您可以在项目的Firebase Database console 中输入这些规则。
【讨论】:
firebase.google.com/docs/reference/security/database/#authtoken 包含auth.token
中可用的文档。
看到这样的例子会很酷,它从数据库的根中提取@gmail.com
,例如my_database/acceptable_domains/
,例如,他们只想将他们的应用程序打开到少数人的电子邮件提供商。例如授权的学校和企业。
是否有不需要对每个域进行硬编码的替代方法 - 例如“gmailUsers”?
您目前无法根据用户的域限制哪些用户可以使用 Firebase 身份验证登录。您可以使用我上面给出的安全规则,根据他们的域限制他们可以访问的数据。
firestore 有什么类似的吗?【参考方案2】:
这里的代码在我的数据库中运行良好,我设置了只有我公司的电子邮件才能读取和写入我的 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.
)
【讨论】:
【参考方案4】:警告:不要相信这个答案。只是在这里讨论。
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 结尾”。
但是,有人指出了一个问题:任何网络客户端都可以在将消息发送到 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)。
【讨论】:
正如您所发现的:.write
规则可以控制谁可以写信到某个位置,.validate
规则可以验证他们写的是有效的电子邮件地址。但是无法在安全规则中验证它实际上是该用户的电子邮件地址。为此,您需要运行一些受信任的代码(通常在服务器上),将这个经过验证的电子邮件地址写入数据库中的(否则为只读)位置。【参考方案5】:
这应该适用于任何寻找 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$");
【讨论】:
【参考方案6】:对于那些真的不想让未经验证的帐户登录的人。也许很脏,但非常有效。
这是我的解决方法(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));
【讨论】:
以上是关于如何将 Firebase 数据库锁定给来自特定(电子邮件)域的任何用户?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Firebase/Google Analytics 分析用户行为并记录来自华为手机的特定事件?
如何将子firebase数据库中的特定名称获取到recyclerview?
Firebase 与 Android Java 中的 Google 云消息传递
如何将来自不同组件的 firebase auth 和 Cloud Firestore 用作单个 Firebase 应用程序