.doc().get() 的 Firebase 权限不足
Firebase insufficient permissions for .doc().get()
我正在尝试对我的应用程序中的用户进行身份验证。我有一个登录屏幕,需要一个电子邮件和密码,然后运行这个:
login2(email: string, password: string): Observable<any> {
const signInObs: Observable<UserCredential> = from(this.fAuth.signInWithEmailAndPassword(email, password));
return signInObs.pipe(take(1), catchError(this.handleError), mergeMap((result: UserCredential) => {
console.log(`done this ONE... ${result.user.uid}`);
return this.firestore.collection('users').doc(result.user.uid).get().pipe(catchError(this.handleError), mergeMap((doc: DocumentSnapshot<any>) => {
console.log(`done this two... ${doc.data().name}`);
return result.user.getIdTokenResult(true).then((token: IdTokenResult) => {
// authenticate the user in the code
console.log(`done this three.. ${token.claims.admin}`);
this.handleAuthentication(
result.user.email,
result.user.uid,
doc.data().name,
token.claims.admin,
token.token
);
}).catch(error => {
throw new Error(error);
});
}));
}));
}
但是旧的 ERROR FirebaseError: Missing or insufficient permissions.
错误发生在 this.firebase.collection('users').doc(result.user.uid).get()
部分。如果没有该部分,这一切都很好 - 即它登录,给我一个令牌等等。一切正常,只是它不允许我访问该用户记录...
我的数据库中的规则是:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match logged in user doc in users collection
match /users/{userId} {
allow create: if request.auth.uid != null;
allow read: if request.auth != null && request.auth.uid == userId;
}
// match docs in the users collection
match /users/{userId} {
allow read, write: if request.auth.uid != null;
}
}
}
关于暗示可能是 FireAuth 和 Firestore 模块未正确通信的回复,这就是 app.module
的样子。这些都是app.module.
中对angular射击模块的引用
import { environment } from 'src/environments/environment';
import { AngularFireModule } from '@angular/fire';
import { AngularFireFunctions } from '@angular/fire/functions';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({
declarations: [
// just components
],
imports: [
// other imports
AngularFireModule.initializeApp(environment.firebaseConfig),
AngularFirestoreModule,
AngularFireAuthModule
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptorService, multi: true},
AuthenticationService,
AngularFireFunctions
],
bootstrap: [AppComponent]
})
export class AppModule { }
以及身份验证服务中的构造函数:
constructor(private fAuth: AngularFireAuth,
private firestore: AngularFirestore,
private router: Router) {
}
我已经 运行 通过模拟器尝试了 id,它似乎应该可以工作。我已经从登录中记录了用户 ID,它与它应该查找的文档名称相同。
这一切看起来应该有效,但实际上没有。我读了很多教程,none 做的事情大相径庭 - 教程之间的差异不一致。
我知道代码的编写方式还不够完美,但我想先让它发挥作用。
我在数据库中的数据结构如下所示:
文件的ID是相关人员的用户ID,我仔细核对了,都是正确的。
仔细检查它是否有效,否则如果我允许通用读写,那么一切都会正常...只有当这些规则出现时它们才不起作用。
您必须指定要匹配的文档,在本例中是所有文档(递归)。这是规则:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match logged in user doc in users collection
match /users/{userId}/{documents=**} {
allow create: if request.auth.uid != null;
allow read: if request.auth.uid == userId;
}
// match docs in the users collection
match /users/{userId}/{documents=**} {
allow read, write: if request.auth.uid != null;
}
}
}
评论后编辑: 根据 https://firebase.google.com/docs/firestore/security/rules-structure#version-2 “在安全规则的版本 2 中,递归通配符匹配零个或多个路径项。 match/cities/{city}/{document=**} 匹配任何子集合中的文档以及 cities 集合中的文档。。我猜想上面的代码解决了子集合问题。如果您仍然遇到问题,请分享您的数据结构,以便人们更好地提供帮助。
第二次编辑: 我想问题的发生是因为 request.auth 为空。如果 request.auth.uid 前有 null pointer.So,Firebase 会抛出错误,你必须检查 request.auth 是否为 null。像那样:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match logged in user doc in users collection
match /users/{userId}/{documents=**} {
allow create: if request.auth != null && request.auth.uid != null;
allow read: if request.auth != null && request.auth.uid == userId;
}
// match docs in the users collection
match /users/{userId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid != null;
}
}
}
第三次编辑: 我昨天遇到了同样的问题(规则很好,当所有规则都设置为真时它会起作用)但奇怪的是它只发生在移动设备上.我在 GitHub 上搜索后发现了这个问题:https://github.com/angular/angularfire/issues/2838。问题是由 Firebase 版本引起的。我的版本是8.6.2所以我降级到8.6.1,问题就没有了。您可以通过以下方式降级:
npm install firebase@8.6.1
我认为这对 Firebase 来说是一个非常严重的问题,它阻碍了人们使用 Firebase 后端开发和维护项目。我希望这也能解决您的问题。
登录绝对是异步的 - 您知道身份验证实际上已经在您的 .get() 之前完成了吗?这是使用身份验证侦听器有用的地方。简单地请求身份验证 [this.fAuth.signInWithEmailAndPassword(email, password)] 是不够的;实际授权与此不同步。 https://firebase.google.com/docs/reference/js/firebase.auth.Auth
我对 login/logout 使用了一系列异步调用和侦听器 - 我正在将其中的 一些 构建到一个库中,但是所需的侦听器和状态更改是超出图书馆范围。
让我们尝试一种 less-Angular 方法,因为您有一个奇怪的 Observable
对象链,但每个操作只执行一次。因此,我们不会将每个步骤转换为 Observable
并链接它们,而是使用 return 原生 Promise
链,稍后您可以将其转换为 Observable
。
此外,收集用户的令牌和他们的用户数据的快照可以同时完成,因为它们彼此不依赖。您也不需要强制刷新用户的 ID 令牌,因为它已经作为上一个登录步骤的一部分进行了刷新。
注意: 不鼓励使用 firebase
作为 AngularFirestore
实例的变量名。 firebase
应视为为 Firebase 客户端 SDK 本身保留,以防止混淆。因此,在此代码示例中,我已将其重命名为 firestore
,但您也可以使用 db
或其他名称。
login2(email: string, password: string): Promise<void> {
return this.fAuth.signInWithEmailAndPassword(email, password)
.then((result) => {
const userDocRef = this.firestore
.collection('users')
.doc(result.user.uid);
return Promise.all([
Promise.resolve(result.user), // User object
result.user.getIdTokenResult(), // User's decoded ID token
userDocRef.ref.get() // User data in Firestore (from the wrapped Firebase SDK DocumentReference)
]);
})
.then(([user, tokenData, userDataSnapshot]) => {
this.handleAuthentication( // <-- if this is a Promise, return it
user.email,
user.uid,
userDataSnapshot.get('name'), // <- more efficient than snap.data().name
tokenData.claims.admin,
tokenData.token
);
});
}
要转换为 Observable
,您需要使用:
login2(email: string, password: string): Observable<any> {
const signInPromise = /* ... code from above ... */
return from(signInPromise);
}
我正在尝试对我的应用程序中的用户进行身份验证。我有一个登录屏幕,需要一个电子邮件和密码,然后运行这个:
login2(email: string, password: string): Observable<any> {
const signInObs: Observable<UserCredential> = from(this.fAuth.signInWithEmailAndPassword(email, password));
return signInObs.pipe(take(1), catchError(this.handleError), mergeMap((result: UserCredential) => {
console.log(`done this ONE... ${result.user.uid}`);
return this.firestore.collection('users').doc(result.user.uid).get().pipe(catchError(this.handleError), mergeMap((doc: DocumentSnapshot<any>) => {
console.log(`done this two... ${doc.data().name}`);
return result.user.getIdTokenResult(true).then((token: IdTokenResult) => {
// authenticate the user in the code
console.log(`done this three.. ${token.claims.admin}`);
this.handleAuthentication(
result.user.email,
result.user.uid,
doc.data().name,
token.claims.admin,
token.token
);
}).catch(error => {
throw new Error(error);
});
}));
}));
}
但是旧的 ERROR FirebaseError: Missing or insufficient permissions.
错误发生在 this.firebase.collection('users').doc(result.user.uid).get()
部分。如果没有该部分,这一切都很好 - 即它登录,给我一个令牌等等。一切正常,只是它不允许我访问该用户记录...
我的数据库中的规则是:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match logged in user doc in users collection
match /users/{userId} {
allow create: if request.auth.uid != null;
allow read: if request.auth != null && request.auth.uid == userId;
}
// match docs in the users collection
match /users/{userId} {
allow read, write: if request.auth.uid != null;
}
}
}
关于暗示可能是 FireAuth 和 Firestore 模块未正确通信的回复,这就是 app.module
的样子。这些都是app.module.
import { environment } from 'src/environments/environment';
import { AngularFireModule } from '@angular/fire';
import { AngularFireFunctions } from '@angular/fire/functions';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({
declarations: [
// just components
],
imports: [
// other imports
AngularFireModule.initializeApp(environment.firebaseConfig),
AngularFirestoreModule,
AngularFireAuthModule
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptorService, multi: true},
AuthenticationService,
AngularFireFunctions
],
bootstrap: [AppComponent]
})
export class AppModule { }
以及身份验证服务中的构造函数:
constructor(private fAuth: AngularFireAuth,
private firestore: AngularFirestore,
private router: Router) {
}
我已经 运行 通过模拟器尝试了 id,它似乎应该可以工作。我已经从登录中记录了用户 ID,它与它应该查找的文档名称相同。
这一切看起来应该有效,但实际上没有。我读了很多教程,none 做的事情大相径庭 - 教程之间的差异不一致。
我知道代码的编写方式还不够完美,但我想先让它发挥作用。
我在数据库中的数据结构如下所示:
文件的ID是相关人员的用户ID,我仔细核对了,都是正确的。
仔细检查它是否有效,否则如果我允许通用读写,那么一切都会正常...只有当这些规则出现时它们才不起作用。
您必须指定要匹配的文档,在本例中是所有文档(递归)。这是规则:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match logged in user doc in users collection
match /users/{userId}/{documents=**} {
allow create: if request.auth.uid != null;
allow read: if request.auth.uid == userId;
}
// match docs in the users collection
match /users/{userId}/{documents=**} {
allow read, write: if request.auth.uid != null;
}
}
}
评论后编辑: 根据 https://firebase.google.com/docs/firestore/security/rules-structure#version-2 “在安全规则的版本 2 中,递归通配符匹配零个或多个路径项。 match/cities/{city}/{document=**} 匹配任何子集合中的文档以及 cities 集合中的文档。。我猜想上面的代码解决了子集合问题。如果您仍然遇到问题,请分享您的数据结构,以便人们更好地提供帮助。
第二次编辑: 我想问题的发生是因为 request.auth 为空。如果 request.auth.uid 前有 null pointer.So,Firebase 会抛出错误,你必须检查 request.auth 是否为 null。像那样:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// match logged in user doc in users collection
match /users/{userId}/{documents=**} {
allow create: if request.auth != null && request.auth.uid != null;
allow read: if request.auth != null && request.auth.uid == userId;
}
// match docs in the users collection
match /users/{userId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid != null;
}
}
}
第三次编辑: 我昨天遇到了同样的问题(规则很好,当所有规则都设置为真时它会起作用)但奇怪的是它只发生在移动设备上.我在 GitHub 上搜索后发现了这个问题:https://github.com/angular/angularfire/issues/2838。问题是由 Firebase 版本引起的。我的版本是8.6.2所以我降级到8.6.1,问题就没有了。您可以通过以下方式降级:
npm install firebase@8.6.1
我认为这对 Firebase 来说是一个非常严重的问题,它阻碍了人们使用 Firebase 后端开发和维护项目。我希望这也能解决您的问题。
登录绝对是异步的 - 您知道身份验证实际上已经在您的 .get() 之前完成了吗?这是使用身份验证侦听器有用的地方。简单地请求身份验证 [this.fAuth.signInWithEmailAndPassword(email, password)] 是不够的;实际授权与此不同步。 https://firebase.google.com/docs/reference/js/firebase.auth.Auth
我对 login/logout 使用了一系列异步调用和侦听器 - 我正在将其中的 一些 构建到一个库中,但是所需的侦听器和状态更改是超出图书馆范围。
让我们尝试一种 less-Angular 方法,因为您有一个奇怪的 Observable
对象链,但每个操作只执行一次。因此,我们不会将每个步骤转换为 Observable
并链接它们,而是使用 return 原生 Promise
链,稍后您可以将其转换为 Observable
。
此外,收集用户的令牌和他们的用户数据的快照可以同时完成,因为它们彼此不依赖。您也不需要强制刷新用户的 ID 令牌,因为它已经作为上一个登录步骤的一部分进行了刷新。
注意: 不鼓励使用 firebase
作为 AngularFirestore
实例的变量名。 firebase
应视为为 Firebase 客户端 SDK 本身保留,以防止混淆。因此,在此代码示例中,我已将其重命名为 firestore
,但您也可以使用 db
或其他名称。
login2(email: string, password: string): Promise<void> {
return this.fAuth.signInWithEmailAndPassword(email, password)
.then((result) => {
const userDocRef = this.firestore
.collection('users')
.doc(result.user.uid);
return Promise.all([
Promise.resolve(result.user), // User object
result.user.getIdTokenResult(), // User's decoded ID token
userDocRef.ref.get() // User data in Firestore (from the wrapped Firebase SDK DocumentReference)
]);
})
.then(([user, tokenData, userDataSnapshot]) => {
this.handleAuthentication( // <-- if this is a Promise, return it
user.email,
user.uid,
userDataSnapshot.get('name'), // <- more efficient than snap.data().name
tokenData.claims.admin,
tokenData.token
);
});
}
要转换为 Observable
,您需要使用:
login2(email: string, password: string): Observable<any> {
const signInPromise = /* ... code from above ... */
return from(signInPromise);
}