离线认证

huangapple go评论104阅读模式
英文:

Offline Authentication

问题

以下是您提供的文本的翻译部分:

In an Angular PWA I'm using firebase security rules to restrict access to nearly all of my data to authenticated users. In an auth-guard I check if the user is authenticated and if not, the user is signed in anonymously (signInAnonymously()) so I ensure that I have a user-id that I can use to flag objects that the user creates. This flag is necessary so I know if the user is the creator and if he is allowed to delete his own comment.

This all works fine - also when I lose connectivity. But if I close the PWA, enable flight-mode and then open the PWA (without connectivity) - signInAnonymously returns an error (because of course the user cannot be signed in on the server). I on the other hand expect to either get the user from LocalStorage / IndexedDb returned or that after opening the app the onAuthStateChanged-Event fires with the locally stored user.

None of this happens (although I see, that the user is in fact stored in indexeddb by Firebase). Docs: Authentication State Persistence also state, that

For a web application, the default behavior is to persist a user's session even after the user closes the browser.

What am I missing? What should I do differently to achieve my goal of:

The PWA should behave like a native app. If I have no connectivity, as I use enableIndexedDbPersistence() for Firestore, the app should load whichever data is in cache and as soon as connectivity is restored, the app should seamlessly use online data.

Edit:
This is the code of my AuthService:

@Injectable()
export class AuthService {
private authState: User = null;

  1. private _isAuthenticated = new ReplaySubject<boolean>();
  2. public isAuthenticated$ = this._isAuthenticated.asObservable();
  3. public get userId() {
  4. if this.authState)
  5. return this.authState.uid;
  6. throw "No User-Id!";
  7. }
  8. constructor(private fAuth: Auth) {
  9. onAuthStateChanged(this.fAuth, async (user) => {
  10. AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged: ${user?.uid}`);
  11. this.authState = user;
  12. try {
  13. if (!this authState) {
  14. this authState = (await signInAnonymously(this fAuth)).user;
  15. }
  16. } catch (e) {
  17. AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged Error: ${e}`);
  18. console.error(e);
  19. } finally {
  20. this _isAuthenticated.next(this.authState != null);
  21. }
  22. });
  23. }

}

Output as follows (from addLogLine-Calls):

  • Open the PWA with connectivity:

onAuthStateChanged: tszjaBTtltVo9XV5B4kHAHnNNt22

  • Close/Kill the PWA, go into Flight-Mode and reopen PWA without connectivity:

onAuthStateChanged: undefined

onAuthStateChanged Error: FirebaseError: Firebase: Error (auth/internal-error).

  • Close/Kill the PWA, go out of Flight-Mode and reopen PWA with connectivity:

onAuthStateChanged: undefined

onAuthStateChanged: D54ENbliWVhyYc9izXjFbtzXhUG2

I just realized that I even get a new anonymous user.

英文:

In an Angular PWA I'm using firebase security rules to restrict access to nearly all of my data to authenticated users. In an auth-guard I check if the user is authenticated and if not, the user is signed in anonymously (signInAnonymously()) so I ensure that I have a user-id that I can use to flag objects that the user creates. This flag is necessary so I know if the user is the creator and if he is allowed to delete his own comment.

This all works fine - also when I lose connectivity. But if I close the PWA, enable flight-mode and then open the PWA (without connectivity) - signInAnonymously returns an error (because of course the user cannot be signed in on the server). I on the other hand expect to either get the user from LocalStorage / IndexedDb returned or that after opening the app the onAuthStateChanged-Event fires with the locally stored user.

None of this happens (although I see, that the user is in fact stored in indexeddb by Firebase). Docs: Authentication State Persistence also state, that

> For a web application, the default behavior is to persist a user's session even after the user closes the browser.

What am I missing? What should I do differently to achieve my goal of:

> The PWA should behave like a native app. If I have no connectivity, as I use enableIndexedDbPersistence() for Firestore, the app should load whichever data is in cache and as soon as connectivity is restored, the app should seamlessly use online data.

Edit:
This is the code of my AuthService:

  1. @Injectable()
  2. export class AuthService {
  3. private authState: User = null;
  4. private _isAuthenticated = new ReplaySubject&lt;boolean&gt;();
  5. public isAuthenticated$ = this._isAuthenticated.asObservable();
  6. public get userId() {
  7. if (this.authState)
  8. return this.authState.uid;
  9. throw &quot;No User-Id!&quot;;
  10. }
  11. constructor(private fAuth: Auth) {
  12. onAuthStateChanged(this.fAuth, async (user) =&gt; {
  13. AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged: ${user?.uid}`);
  14. this.authState = user;
  15. try {
  16. if (!this.authState) {
  17. this.authState = (await signInAnonymously(this.fAuth)).user;
  18. }
  19. } catch (e) {
  20. AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged Error: ${e}`);
  21. console.error(e);
  22. } finally {
  23. this._isAuthenticated.next(this.authState != null);
  24. }
  25. });
  26. }
  27. }

Output as follows (from addLogLine-Calls):

  • Open the PWA with connectivity:
    > onAuthStateChanged: tszjaBTtltVo9XV5B4kHAHnNNt22
  • Close/Kill the PWA, go into Flight-Mode and reopen PWA without connectivity:
    > onAuthStateChanged: undefined
    >
    > onAuthStateChanged Error: FirebaseError: Firebase: Error (auth/internal-error).
  • Close/Kill the PWA, go out of Flight-Mode and reopen PWA with connectivity:
    > onAuthStateChanged: undefined
    >
    > onAuthStateChanged: D54ENbliWVhyYc9izXjFbtzXhUG2

I just realized that I even get a new anonymous user.

答案1

得分: 0

这似乎是你的代码在页面加载时总是调用 signInAnonymously 来匿名登录用户。实际上,这是一种反模式,因为这意味着 SDK 会向服务器发出调用,这就解释了为什么你的代码失败。

恢复用户的登录状态的惯用方法是使用 onAuthStateChanged 监听器,如文档中的第一个代码示例所示,用于获取当前用户的信息(https://firebase.google.com/docs/auth/web/manage-users#get_the_currently_signed-in_user):

  1. import { getAuth, onAuthStateChanged } from "firebase/auth";
  2. const auth = getAuth();
  3. onAuthStateChanged(auth, (user) => {
  4. if (user) {
  5. // 用户已登录,查看文档以获取可用属性的列表
  6. // https://firebase.google.com/docs/reference/js/firebase.User
  7. const uid = user.uid;
  8. // ...
  9. } else {
  10. // 用户已注销
  11. // ...
  12. }
  13. });

只有在没有当前用户时,才需要调用 signInAnonymously(或任何其他登录提供者)来首次登录。


更新 2022-04-04:我尝试在这里复制问题:https://stackblitz.com/edit/auth-v9-restore。

当我使用右侧的小 ↻ 图标刷新预览面板时,它会重新加载匿名用户,无论是在我的没有Wi-Fi连接的笔记本电脑上,还是在飞行模式下的手机上。

英文:

It sounds like your code always calls signInAnonymously when the page loads, to sign in the user anonymously. That's actually an anti-pattern, as it means the SDK will call to the server, which explains why your code fails.

The idiomatic way to restore the sign-in state of your user is to use an onAuthStateChange listener, as shown in this first code sample from the documentation on getting the current user:

  1. import { getAuth, onAuthStateChanged } from &quot;firebase/auth&quot;;
  2. const auth = getAuth();
  3. onAuthStateChanged(auth, (user) =&gt; {
  4. if (user) {
  5. // User is signed in, see docs for a list of available properties
  6. // https://firebase.google.com/docs/reference/js/firebase.User
  7. const uid = user.uid;
  8. // ...
  9. } else {
  10. // User is signed out
  11. // ...
  12. }
  13. });

Then only when there is no current user, will you want to call signInAnonymously (or any other sign-in provider) to sign in for the first time.


Update 2022-04-04: I tried to reproduce the problem here: https://stackblitz.com/edit/auth-v9-restore.

When I refresh the preview panel with the little ↻ icon on the right, it reloads the anonymous user for me both on my laptop with the wifi disabled, and on my phone in airplane mode.

离线认证

答案2

得分: 0

无法精确确定,但在删除了node_modules/package-lock.json后(并使用这个更新@angular/*软件包从12.2.515.2.7),似乎正常工作。最近一定有一个错误修复。

英文:

I cannot pinpoint it exactly but after deleting node_modules/package-lock.json (and with this updating @angular/* packages from 12.2.5 to 15.2.7) it seems to work fine. There must have been a bugfix recently.

huangapple
  • 本文由 发表于 2023年3月31日 18:04:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897248.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定