Проблема аутентификации - порядок выполнения Observables и Promises (Angular / REST) - PullRequest
0 голосов
/ 11 июня 2019

Я использую Angular 7.

Я новичок в Angular, и в агентстве, где я работаю, мы собираемся создать новое угловое приложение.

Мой коллега создал бэкэнд(Restful), и я начал с функцией аутентификации.Итак, прежде всего у нас есть макет с верхней панелью и боковой панелью, они есть на каждом экране.

После того, как я сделал макет, я начал с компонента входа, я также создал JWT-перехватчик, чтобы добавить токенв любой заголовок.И создал AuthGuard для защиты большинства путей.

Я добавил AuthenticationService с функциями login, logout и isAuthenticated.

export class AuthenticationService {
  public currentUserSubject: BehaviorSubject<User>;
  public currentUser: Observable<User>;
  returnUrl: string;

  constructor(private http: HttpClient, private userService: UserService,  private router: Router, private route: ActivatedRoute) {
    if (localStorage.getItem("currentUser")) {
      const userId = JSON.parse(localStorage.getItem("currentUser")).id;
      userService.getById(userId).subscribe((data) => {
        this.currentUserSubject = new BehaviorSubject<User>(data as User);
        this.currentUser = this.currentUserSubject.asObservable();
      });
    }
  }

  isAuthenticated() {
    const authState = new Subject<boolean>();

    this.currentUser.subscribe(data => {
      console.log(data);
      if (data) {
        authState.next(true);
      } else {
        authState.next(false);
      }
    });

    return authState.asObservable();
  }

  login(email: string, password: string) {
    return this.http.post<any>(`http://pitchbook.localhost/authentication_token`, {
      username: email,
      password
    })
        .pipe(map(object => {
          // login successful if there's a jwt token in the response
          if (object.user && object.token) {
            this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';

            const jsonObject = {
              id: object.user.id,
              token: object.token
            };

            // store user details and jwt token in local storage to keep user logged in between page refreshes
            localStorage.setItem('currentUser', JSON.stringify(jsonObject));

            return jsonObject;
          }

          return object;
        }));
  }

  logout() {
    // remove user from local storage to log user out
    localStorage.removeItem('currentUser');
    this.currentUserSubject.next(null);
    location.reload(true);
  }
}

И затем я вызвал login () в форме SubmitLoginComponent.

  onSubmit() {
    // stop here if form is invalid
    if (this.loginForm.invalid) {
      return;
    }

    this.loading = true;
    this.authenticationService.login(this.loginF.email.value, this.loginF.password.value)
        .pipe(first()).subscribe(
        (object) => {
          this.userService.getById(object.id as number).subscribe((data) => {
            this.authenticationService.currentUserSubject.next(data as User);
            this.authenticationService.currentUser = this.authenticationService.currentUserSubject.asObservable();

            console.log(this.authenticationService.currentUser);

            this.router.navigate(["/dashboard"]);
            this.alertService.success("Success");
          });
        },
        (error) => {
          this.loading = false;
          this.alertService.error("Error");
        }
    );
  }

Итак, проблема в том, что когда я вхожу в систему, получение пользователя с идентификатором занимает слишком много времени, и переход к «/ dashboard» происходит раньше.После этого AuthGuard пытается получить currentUser службы AuthenticationService, но его все еще нет, и поэтому я получаю ответный удар к «/ login» и должен снова войти в систему.После того, как меня выгнали "/ login", currentUser установлен в службе AuthGuard, но сейчас уже слишком поздно, и я не могу подписаться на него, потому что он не определен при первом вызове.

Я пытался получитьПользователь внутри канала в функции входа в систему AuthenticationService, но это не сработало.

В результате я ожидаю, что при нажатии кнопки входа в систему установлено значение currentUser (получить пользователя из API с идентификатором)(потому что объект пользователя довольно большой и не должен быть полностью в ответ на запрос аутентификации))

Я перехожу на / панель инструментов и в верхней панели я вижу свое имя пользователя.

Но вскрытый, AuthGuard должен следить, если пользователь прошел проверку подлинности, если нет, перейдите к /login.

После обновления страницы я хочу оставаться в системе

Надеюсь, вы, ребята, понимаете, о чем я, если не стесняйтесь спрашивать.Я могу добавить некоторые строки кода или при необходимости показать другие компоненты.

1 Ответ

0 голосов
/ 11 июня 2019

Есть несколько проблем с тем, как вы используете RxJS. Вы не должны перезаписывать переменные Observables таким образом.

В AuthenticationService объявить currentUser таким образом:

  public readonly currentUser = this.currentUserSubject.asObservable();

И удалите следующее из метода onSubmit().

this.authenticationService.currentUser = this.authenticationService.currentUserSubject.asObservable();

Метод isAuthenticated написан плохо (утечка подписки), лучшим способом может быть:

  isAuthenticated() {
    return this.currentUser.pipe(map(user => !!user));
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...