【问题标题】:Angular 6: Get Token from localStorage After RefreshAngular 6:刷新后从localStorage获取令牌
【发布时间】: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');
  }
}

【问题讨论】:

    标签: angular typescript authentication jwt local-storage


    【解决方案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 路径使用相同的保护。您确实必须添加重定向。对于那个很抱歉。我会更新我的答案
    猜你喜欢
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2018-12-01
    • 2019-03-28
    • 1970-01-01
    相关资源
    最近更新 更多