离线认证

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

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;

private _isAuthenticated = new ReplaySubject<boolean>();
public isAuthenticated$ = this._isAuthenticated.asObservable();

public get userId() {
    if this.authState)
        return this.authState.uid;

    throw "No User-Id!";
}

constructor(private fAuth: Auth) {
    onAuthStateChanged(this.fAuth, async (user) => {
        AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged: ${user?.uid}`);

        this.authState = user;
        try {
            if (!this authState) {
                this authState = (await signInAnonymously(this fAuth)).user;
            }
        } catch (e) {
            AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged Error: ${e}`);
            console.error(e);
        } finally {
            this _isAuthenticated.next(this.authState != null);
        }
    });
}

}

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:

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

    private _isAuthenticated = new ReplaySubject&lt;boolean&gt;();
    public isAuthenticated$ = this._isAuthenticated.asObservable();

    public get userId() {
        if (this.authState)
            return this.authState.uid;

        throw &quot;No User-Id!&quot;;
    }

    constructor(private fAuth: Auth) {
        onAuthStateChanged(this.fAuth, async (user) =&gt; {
            AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged: ${user?.uid}`);

            this.authState = user;
            try {
                if (!this.authState) {
                    this.authState = (await signInAnonymously(this.fAuth)).user;
                }
            } catch (e) {
                AdminConsoleDialogComponent.addLogLine(`onAuthStateChanged Error: ${e}`);
                console.error(e);
            } finally {
                this._isAuthenticated.next(this.authState != null);
            }
        });
    }
}

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):

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth();
onAuthStateChanged(auth, (user) => {
  if (user) {
    // 用户已登录,查看文档以获取可用属性的列表
    // https://firebase.google.com/docs/reference/js/firebase.User
    const uid = user.uid;
    // ...
  } else {
    // 用户已注销
    // ...
  }
});

只有在没有当前用户时,才需要调用 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:

import { getAuth, onAuthStateChanged } from &quot;firebase/auth&quot;;

const auth = getAuth();
onAuthStateChanged(auth, (user) =&gt; {
  if (user) {
    // User is signed in, see docs for a list of available properties
    // https://firebase.google.com/docs/reference/js/firebase.User
    const uid = user.uid;
    // ...
  } else {
    // User is signed out
    // ...
  }
});

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:

确定