Angular 6:刷新后从localStorage获取令牌

Posted

技术标签:

【中文标题】Angular 6:刷新后从localStorage获取令牌【英文标题】:Angular 6: Get Token from localStorage After Refresh 【发布时间】:2019-04-16 08:50:22 【问题描述】:

编辑:我用 PierreDuc 给我的答案更新了代码。他的解决方案对我有用。我编辑了代码,这样每个人都可以看到工作代码

我正在使用 canActivate 和 canActivateChild 来了解是否有人拥有我的网站的令牌,我想阻止任何没有令牌的人。 我将 localStorage 用于用户数据和令牌。

当我尝试使用用户 id:1 登录时,守卫导航到未找到的页面,但在我刷新页面后,我可以访问该页面。 当我使用调试器时,我看到在刷新之前 localStorage 是空的,但在刷新之后有值。

为什么会这样?我该如何解决? 这是相关代码:

app-routing.module.ts

const appRoutes: Routes = [
   path: 'login/:id', canActivate: [AuthGuard], children: [] ,
   path: '', canActivateChild: [AuthGuard], children: [
     path: '', redirectTo: '/courses', pathMatch: 'full' ,
     path: 'courses', component: CourseListComponent,  pathMatch: 'full',
     path: 'courses/:courseId', component: CourseDetailComponent, pathMatch: 'full' ,
     path: 'courses/:courseId/unit/:unitId', component: CoursePlayComponent,
      children: [
         path: '', component: CourseListComponent ,
         path: 'lesson/:lessonId', component: CourseLessonComponent, data: type: 'lesson' ,
         path: 'quiz/:quizId', component: CourseQuizComponent, data: type: 'quiz' 
      ]
    ],
   path: '**', component: PageNotFoundComponent, pathMatch: 'full' ];

auth.guard.ts

export class AuthGuard implements CanActivate , CanActivateChild 

    constructor(private authUserService: AuthUserService, private router: Router)    

    canActivate(route: ActivatedRouteSnapshot, state:
    RouterStateSnapshot): boolean |
    Observable<boolean> | Promise<boolean> 
      // save the id from route snapshot
      const id = +route.params.id;

      // if you try to logging with id
      if (id) 
        this.router.navigate(["/courses"]);
        return this.authUserService.login(id);
      

      // if you already logged and just navigate between pages
      else if (this.authUserService.isLoggedIn())
         return true;

      else 
        this.router.navigate(["/page_not_found"]);
        return false;
      
     

      canActivateChild(route: ActivatedRouteSnapshot,state: RouterStateSnapshot): boolean |
      Observable<boolean> | Promise<boolean> 
         return this.canActivate(route, state);
       


auth-user.service.ts

import  Injectable, OnDestroy  from '@angular/core';
import  Observable , BehaviorSubject  from 'rxjs';
import  LocalStorage  from '@ngx-pwa/local-storage';
import  of  from 'rxjs';
import  map  from 'rxjs/operators';
import  catchError, groupBy  from 'rxjs/operators';

import  UserService  from './user.service';
import  IUser  from './user';

@Injectable()
export class AuthUserService implements OnDestroy 

  private user: IUser;
  private errorMessage: string;

  constructor(private userService: UserService)  

  // store the session and call http get
  login(id: number) 
    return this.userService.getUser(id).pipe(
      map((user) => 
        this.user = user;
        localStorage.setItem('user', JSON.stringify(this.user));
        localStorage.setItem('token', 'JWT');
        return true;
      ),
      catchError((error) => 
        this.errorMessage = <any>error;
        return of(false);
      )
    );
  

  isLoggedIn() 
   return !!localStorage.getItem('token');
  

  ngOnDestroy() 
    localStorage.removeItem('user');
    localStorage.removeItem('token');
  

【问题讨论】:

【参考方案1】:

userService.getUser 是异步的,它不会完成,并且会在您检查后设置您的 localStorage。

将您的 authService 更改为:

login(id: number) 
  return this.userService.getUser(id).pipe(
    map((user) => 
      this.user = user;
      localStorage.setItem('user', JSON.stringify(this.user));
      localStorage.setItem('token', 'JWT');
      return true;
    ),
    catchError((error) => 
      this.errorMessage = <any>error;
      return of(false);
    )
  );

然后更新你的警卫:

if (id) 
  this.router.navigate(["/courses"]);
  return this.authUserService.login(id);

【讨论】:

我按照你说的做了,现在当我尝试访问 localhost:4200/login/1 => ERROR 错误:未捕获(承诺):ReferenceError:未定义 of 是来自 rxjs 的运算符,您必须使用 import of from 'rxjs'; 导入它,catchErrormap 相同。 CatchError 必须返回一个 observable map 更新 observable 发出的值。订阅触发冷可观察..这不是你想要的,但只有在角度检查守卫时 是的..你必须从rxjs/operators导入它 啊,是的,我看错了你的路线。您也对 login/:id 路径使用相同的保护。您确实必须添加重定向。对于那个很抱歉。我会更新我的答案

以上是关于Angular 6:刷新后从localStorage获取令牌的主要内容,如果未能解决你的问题,请参考以下文章

除非我刷新页面,否则 Javascript localStorage 在其他组件中不可用

Vue.js 硬刷新后从输入中重置状态值。如何解决?

获取图像后从其 imageView 刷新 UITableViewCell 布局

刷新页面导致 404 错误-AWS-Angular 6

Angular 6 项目刷新后显示 404 错误

Angular 6 - 更改变量但不刷新视图