如何将 Firebase 数据库锁定到来自特定(电子邮件)域的任何用户?
How do I lock down Firebase Database to any user from a specific (email) domain?
我有一个使用 Firebase 数据库的小型个人 Firebase 网络应用程序。我想将此应用程序保护(锁定)给来自单个特定域的任何用户。我想使用 Google 进行身份验证。我不清楚如何配置规则说 "only users from a single, specific domain (say @foobar.com
) can read and write to this database"。
(我看到的部分问题:很难 bootstrap 一个具有足够信息的数据库来使这个用例工作。我需要在身份验证时知道用户的电子邮件,但是 auth
对象不包含电子邮件。这似乎是先有鸡还是先有蛋的问题,因为我需要编写引用数据库中数据的 Firebase 规则,但该数据尚不存在,因为我的用户无法写入到数据库。)
如果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')"
}
}
}
}
我相信上面说的 "only allow people to create a new user if they are authenticated by Google, are trying to write into the database node for themselve ($user_id === auth.uid
) and their email ends in 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)。
如果您使用的是新的 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 数据库的数据。
{
"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.
})
}
}
对于真正不想让未经验证的帐户登录的人来说。可能很脏,但非常有效。
这是我的解决方法(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));
受 Frank van Puffelen 的回答启发,这应该适用于寻找 Cloud 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$");
}
}
}
我有一个使用 Firebase 数据库的小型个人 Firebase 网络应用程序。我想将此应用程序保护(锁定)给来自单个特定域的任何用户。我想使用 Google 进行身份验证。我不清楚如何配置规则说 "only users from a single, specific domain (say @foobar.com
) can read and write to this database"。
(我看到的部分问题:很难 bootstrap 一个具有足够信息的数据库来使这个用例工作。我需要在身份验证时知道用户的电子邮件,但是 auth
对象不包含电子邮件。这似乎是先有鸡还是先有蛋的问题,因为我需要编写引用数据库中数据的 Firebase 规则,但该数据尚不存在,因为我的用户无法写入到数据库。)
如果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')"
}
}
}
}
我相信上面说的 "only allow people to create a new user if they are authenticated by Google, are trying to write into the database node for themselve ($user_id === auth.uid
) and their email ends in 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)。
如果您使用的是新的 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 数据库的数据。
{
"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.
})
}
}
对于真正不想让未经验证的帐户登录的人来说。可能很脏,但非常有效。
这是我的解决方法(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));
受 Frank van Puffelen 的回答启发,这应该适用于寻找 Cloud 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$");
}
}
}