Angular 2 - Firebase 在页面刷新时保持登录状态

Posted

技术标签:

【中文标题】Angular 2 - Firebase 在页面刷新时保持登录状态【英文标题】:Angular 2 - Firebase maintaining logged in state on page refresh 【发布时间】:2017-10-21 06:09:06 【问题描述】:

所以我真的很接近解决这个问题。基本上,我有登录工作,我有代码设置来监视 onAuthStateChanged,但问题是当我刷新页面时,即使用户当前已登录,它仍然重定向到 /login 页面,因为身份验证守卫我已经设置,检查用户是否已登录。

我有一个身份验证服务设置来执行所有身份验证检查。

在我的身份验证服务构造函数中,我设置了onAuthStateChanged 代码:

constructor(
    private auth: AngularFireAuth,
    private router:Router,
    private db:AngularFireDatabase,
  ) 

    firebase.auth().onAuthStateChanged(function(user) 
     if (user) 
       // What do I need to put here to ensure that the auth guard goes to the intended route?
     
    );

  

这是我的 auth guard 的 canActivate() 方法:

 canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean> 

      if(this.authService.getAuthenticated()) 
        return Observable.of(true);
       else 
        this.router.navigate(['/login']);
      
    

这里是getAuthenticated() 方法:

getAuthenticated() 
    return firebase.auth().currentUser;
  

更新:

这里是用户实际登录时调用的方法。在实际组件中,这里是登录方法:

login(data, isValid) 
    if(isValid) 

      this.authService.login(data.email, data.password)
          .then(
              (data) => 
                console.log('data', data);
                this.router.navigate(['/projects'])
              , error => 
                this._utilities.createToasty(
                  msg: "The email/password combination is incorrect.",
                  type: "error"
                );
              
          );
    
  

在身份验证服务中,登录方法如下:

login(email, password) 
    return firebase.auth().signInWithEmailAndPassword(email, password);
  

所以现在,我不完全确定我需要将哪些代码放在哪里,以确保当我的用户刷新页面时,身份验证守卫会注意到这一点并实际上允许用户转到路由而不是总是重定向到/login 路由。

想法?

【问题讨论】:

您能发布您的身份验证方法吗? IE用户按下登录时调用的方法 当然。我已经继续添加它们。你知道我需要在这里做什么吗? 嗨,Stevie,您是否设法解决了这个问题,如果可以,请您发布答案。谢谢 How do I keep a user logged into a firebase app after refresh?的可能重复 【参考方案1】:

我真的不知道答案,因为我不使用 firebase 所以这些是更多的指针

猜一猜:用户处于中间状态

当 canActivate 方法运行时,在后台运行身份验证的函数尚未运行。因此,当前用户尚未设置。我猜firebase只是去你的本地存储并检查令牌是否有效。如果它是这样做的,那么只需确保这发生在 canActivate 之前。

但是,如果它是异步的,那么它可以在之前运行并且当前用户仍然未定义,这是很有可能的。然后你必须确保 canActivate 在它解决后运行。

实际上,更好的是:在你的 can activate 方法中使用 observable,如下所示:

here

here

代码:

 canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) 
    return this.af.auth.map((auth) => 
        if (!auth) 
          this.router.navigateByUrl('login');
          return false;
        
        return true;
    ).take(1);
  

猜测 2:你必须在本地存储中存储一些东西。

那些身份验证服务通常需要在本地存储中存储一个令牌,然后这个令牌用于在页面刷新时对用户进行身份验证。我能读到的内容是在后台使用 firebase 完成的。您仍然可以检查本地存储/会话存储,以确保您在那里看到信息。

如果您在 localStorage/sessionStorage 中没有看到任何相关内容,那么您很可能在登录时必须在其中添加一些内容。

【讨论】:

非常感谢您对此进行调查。有趣的是,其中一个链接实际上是我的旧帖子,但它让我想起了我可以尝试的东西,根据你的建议。所以一次,再次谢谢你:)【参考方案2】:

我遇到了和你一样的问题,我用 localStorage 解决了这个问题:

login(email, password): Observable<AuthInfo> 
    return this.fromFirebaseAuthPromise(this.afAuth.auth.signInWithEmailAndPassword(email, password));

我刚刚添加了localStorage.setItem("user", this.afAuth.auth.currentUser.uid); 登录响应和localStorage.removeItem("user"); 注销方法。

fromFirebaseAuthPromise(promise): Observable<any> 

const subject = new Subject<any>();

promise
  .then(res => 
      const authInfo = new AuthInfo(this.afAuth.auth.currentUser.uid);
      this.authInfo$.next(authInfo);
      subject.next(res);
      subject.complete();
      localStorage.setItem("user", this.afAuth.auth.currentUser.uid);
    ,
    err => 
      this.authInfo$.error(err);
      subject.error(err);
      subject.complete();
    );

    return subject.asObservable();




logout() 
    this.afAuth.auth.signOut();
    localStorage.removeItem("user");
    this.authInfo$.next(AuthService.UNKNOWN_USER);
    this.router.navigate(['/login']);

并将canActivate() 方法更改为以下内容:

canActivate() 
        //you can check token is exists or not here
        if (localStorage.getItem('user')) 
            console.log("user ist logged in ....", localStorage.getItem('user'));

            return true;
         else 
            console.log("user is not logged in");

            this.router.navigate(['/login']);
            return false;
        
    

【讨论】:

这是我选择的答案。谢谢你,爱发迪。我会更进一步,使用 momentjs 和选择的到期日期。我用最少的额外代码在本地存储中保存了 3 天。【参考方案3】:
firebase.auth().onAuthStateChanged(function (user) 
   console.log('onAuthStateChanged: ', user);
);

【讨论】:

【参考方案4】:

让我尝试通过将用户数据保存在本地存储中来解决这个问题。 当用户登录时,我的逻辑非常简单,我们会将用户数据保存在本地存储中,这样即使在页面重新加载后我们也将拥有用户状态。

userData: any;

constructor(
    public afAuth: AngularFireAuth
)     
    this.afAuth.authState.subscribe(user => 
      if (user) 
        localStorage.setItem('user', JSON.stringify(this.userData));
        JSON.parse(localStorage.getItem('user'));
       else 
        localStorage.setItem('user', null);
        JSON.parse(localStorage.getItem('user'));
      
    )
  

【讨论】:

请注意,网站规则要求您披露与您链接到的网站的从属关系,否则将被视为垃圾邮件。【参考方案5】:

在 setTimeout 中编写代码。因为 刷新页面后出现此问题。

setTimeout(()=>
console.log("currentUser", firebase.auth().currentUser);
,1000)

【讨论】:

以上是关于Angular 2 - Firebase 在页面刷新时保持登录状态的主要内容,如果未能解决你的问题,请参考以下文章

在 Firebase 上重新加载 Angular 页面时找不到页面

Firebase 托管在部署 Angular 6 应用程序后显示欢迎页面?

Angular 应用程序中的 Firebase UI Auth 小部件

如何在angular4的firebase电话身份验证中重新发送短信验证?

在 Angular 11 网站上使用 Firestore 和 Firebase 存储进行图像上传功能导致来自 Firebase 的不安全规则通知

使用 Angular 2 添加 Firebase 的单元测试