Как создать asyn c auth-guard для одной из загруженных вкладок ioni c - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть простое приложение с вкладками Ioni c 4/5 (я начал с их вкладки стартер). Я хотел бы сделать одну из вкладок охраняемой аутентификацией. Вот чего я хочу достичь:

  • иметь одну из вкладок, зарезервированных для зарегистрированных пользователей, управления профилями, управления учетными записями и т. Д. c ..
  • , поэтому, когда пользователь нажимает третья вкладка, страница по умолчанию - это «профиль», который охраняется AuthGuard, если в хранилище ioni c нет ни одного пользователя, вместо этого перенаправьте на страницу входа / регистрации

до сих пор пробовал:

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  static STORAGE_KEY = 'auth-user';

  user: BehaviorSubject<User> = new BehaviorSubject(null);
  redirectUrl: string;

  constructor(
    @Inject(ROUTES_CONFIG)
    private readonly ROUTES: AppRoutes,
    private readonly router: Router,
    private readonly storage: Storage,
    private readonly platform: Platform,
    private readonly http: HttpClient
  ) {
    this.platform.ready().then(() => {
      this.checkUser();
    });
  }

  async checkUser() {
    const user = await this.storage.get(AuthService.STORAGE_KEY) as User;
    if (user) {
      this.user.next(user);
    }
  }

  login(credentials): Observable<any> {
    const loginObservable = this.http.post(`http://localhost:3000/auth/login`, credentials);

    loginObservable.subscribe(async (user: User) => {
      await this.storage.set(AuthService.STORAGE_KEY, user);
      this.user.next(user);
      this.router.navigateByUrl(this.redirectUrl || this.ROUTES.AUTH);
    });

    return loginObservable;
  }

  async logout(): Promise<void> {
    await this.storage.remove(AuthService.STORAGE_KEY);
    this.user.next(null);
    this.router.navigateByUrl(this.ROUTES.LOGIN);
  }

  isLoggedIn(): Observable<User> {
    return this.user;
  }

}

И охранник:

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Promise<boolean> | Observable<boolean> | boolean {
    let url: string = state.url;

    // Store the attempted URL for redirecting
    this.authService.redirectUrl = url;

    return this.authService
      .isLoggedIn()
      .pipe(
        skip(1),
        map(user => {
          if (user) {
            console.log('authenticated');
            return true;
          }

          console.error('Not authenticated, redirecting to login');
          this.router.navigateByUrl(this.ROUTES.LOGIN);
          return false;
        })
      )
  }

Проблема с этим, когда аутентифицируется однажды, authguard никогда не входит в map. Я поставил skip(1), потому что хотел пропустить начальное значение null. Как я могу «отложить» AuthGuard, пока мой AuthService не проверит, присутствует ли пользователь в хранилище, потому что в конце концов это то, что я хочу сделать.

1 Ответ

0 голосов
/ 21 февраля 2020

Я не мог решить это таким образом, но я мог решить это другим способом, вот как:

Ранее у меня был

  • модуль tab1, модуль tab2, модуль tab3 ( профиль, логин, регистрация)
  • Страница профиля охранялась AuthGuard. Если не было найдено ни одного пользователя, перенаправленного на логин, * из AuthGuard был вызван
  • AuthService ->, укажите состояние пользователя как BehaviorObject -> см. Мой оригинальный вопрос

Это то, как я изменился

  • модуль tab1, тот же модуль tab2
  • модуль tab3 (страница профиля)
  • вход в систему, регистрация в модуле root,
  • , создан APP_INITIALIZER где я проверяю, есть ли пользователь в хранилище
  • создал новый UserService просто для хранения пользователя
  • AuthService просто управляет перенаправлениями, логином, регистрируется

-связанные коды

app.module.ts -> в провайдерах

    BootstrappingService,
    {
      provide: APP_INITIALIZER,
      useFactory: (bootstrappingService: BootstrappingService) =>
        () => bootstrappingService.initApp(),
      deps: [BootstrappingService],
      multi: true
    },

BootstrappingService.ts

@Injectable()
export class BootstrappingService {

  constructor(
    private readonly storage: Storage,
    private readonly platform: Platform,
    private readonly userService: UserService
  ) {}

  async initApp() {
    await this.platform.ready();
    const user: User = await this.storage.get(AuthService.STORAGE_KEY);
    if (user) {
      this.userService.user.next(user);
    }
  }
}

UserService.ts -> удержание аутентифицированного (пользовательского) состояния

@Injectable({
  providedIn: 'root'
})
export class UserService {

  user: BehaviorSubject<User> = new BehaviorSubject(null);

  constructor() { }
}

AuthService.ts

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  static STORAGE_KEY = 'auth-user';

  redirectUrl: string;

  constructor(
    @Inject(ROUTES_CONFIG)
    private readonly ROUTES: AppRoutes,
    private readonly router: Router,
    private readonly storage: Storage,
    private readonly userService: UserService,
    private readonly http: HttpClient
  ) {}

  login(credentials): Observable<any> {
    const loginObservable = this.http.post(`http://localhost:3000/auth/login`, credentials);
    loginObservable.subscribe(async (user: User) => {
      await this.storage.set(AuthService.STORAGE_KEY, user);
      this.userService.user.next(user);
      this.router.navigateByUrl(this.redirectUrl || this.ROUTES.PROFILE);
    });
    return loginObservable;
  }

  async logout(): Promise<void> {
    await this.storage.remove(AuthService.STORAGE_KEY);
    this.userService.user.next(null);
    this.router.navigateByUrl(this.ROUTES.HOME);
  }
}

и, наконец, AuthGuard.ts

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(
    @Inject(ROUTES_CONFIG)
    private readonly ROUTES: AppRoutes,
    private readonly userService: UserService,
    private readonly authService: AuthService,
    private readonly router: Router
  ) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Promise<boolean> | Observable<boolean> | boolean {
    let url: string = state.url;

    // Store the attempted URL for redirecting
    this.authService.redirectUrl = url;

    return this.userService.user
      .asObservable()
      .pipe(
        map((user: User) => {
          if (user) {
            console.log('authenticated');
            return true;
          }

          console.error('Not authenticated, redirecting to login', user);
          this.router.navigateByUrl(this.ROUTES.LOGIN);
          return false;
        })
      )
  }
}

Теперь моя защищенная третья вкладка, кажется, обрабатывает вход / выход из системы правильно изложить. Нажатие refre sh на защищенном маршруте работает также.

...