Заголовок остается неизменным после проверки входа пользователя в систему

#angular #typescript #express

#angular #typescript #экспресс

Вопрос:

В настоящее время я использую Angular 11 на интерфейсе и Express на серверной части. Я пытаюсь узнать, вошел ли пользователь в систему, чтобы я мог показать правильный заголовок. После входа в систему браузер перенаправляет меня на домашнюю страницу, и в браузере устанавливается файл cookie, но в заголовке ничего не меняется. После того, как я нажму кнопку выхода из системы, файл cookie будет удален, а заголовок останется прежним. Я попытался отладить его с помощью chrome dev tools и зарегистрировать переменную isLogged $, но она продолжает показывать мне, что она не определена. Я думаю, что я делаю что-то не так с BehaviourSubject .

Я действительно надеюсь, что кто-нибудь поможет мне найти мою ошибку, поскольку я только начал с Angular.

Я приложу некоторые файлы для лучшего объяснения.

auth.service.ts

 import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable';
import { catchError, tap, map } from 'rxjs/operators';
import { IUser } from '../shared/interfaces';

@Injectable()
export class AuthService {

  currentUser: IUser | null;

  private _currentUser: BehaviorSubject<IUser | null> = new BehaviorSubject(undefined);
  currentUser$ = this._currentUser.asObservable();
  isLogged$ = this.currentUser$.pipe(map(user => !!user));

  constructor(private http: HttpClient) { }

  login(data: any): Observable<any> {
    return this.http.post(`/user/login`, data).pipe(
      tap((user: IUser) =>
        this._currentUser.next(user))
    );
  }

  signup(data: any): Observable<any> {
    return this.http.post(`/user/signup`, data).pipe(
      tap((user: IUser) => this._currentUser.next(user))
    );
  }

  logout(): Observable<any> {
    return this.http.post(`/user/logout`, {}).pipe(
      tap((user: IUser) => this._currentUser.next(null))
    );
  }

  authenticate(): Observable<any> {
    return this.http.get(`/user/verify`).pipe(
      tap((user: IUser) => this._currentUser.next(user)),
      catchError(() => {
        this._currentUser.next(null);
        return [null];
      })
    );
  }
}
 

navigation.component.ts

 import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {

  isLogged$ = this.authService.isLogged$;

  constructor(
    private authService: AuthService,
    private router: Router) { }

  ngOnInit(): void {
  }
  
  logoutHandler(): void {
    this.authService.logout().subscribe(() => this.router.navigate(['/']));
  }
}
 

navigation.component.html

 <nav class="navigation-wrapper">
    <article>
        <ul>
            <li class="home">
                <a href="/">Home</a>
            </li>
            <li *ngIf="!isLogged$" class="login">
                <a href="/login">Login</a>
            </li>
            <li *ngIf="!isLogged$" class="sign-up">
                <a href="/signup">Sign Up</a>
            </li>
            <li *ngIf="isLogged$" class="my-cities">
                <a href="/my-cities">My Cities</a>
            </li>
            <li *ngIf="isLogged$" class="account">
                <a href="/account">Account</a>
            </li>
            <li *ngIf="isLogged$" class="logout">
                <a (click)="logoutHandler()">Logout</a>
            </li>
        </ul>
    </article>
</nav>
 

auth.interceptor.ts

 import { Injectable, Provider } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs';

import { environment } from '../../environments/environment';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    apiUrl = environment.apiURL;

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        req = req.clone({
            url: `${this.apiUrl}${req.url}`,
            withCredentials: true
        });
        return next.handle(req);
    }
}

export const authInterceptorProvider: Provider = {
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true
};
 

user.js (внутренний контроллер)

 const User = require('../models/User');

const utils = require('../utils');
const authCookieName = process.env.authCookieName;

module.exports = {
    get: async (req, res, next) => {
        try {
            const { id } = req.params;

            const user = await User.findById(id).populate('followedCities').lean();

            res.send(user);
        } catch (e) {
            console.error(e);
            next();
        }
    },

    post: {
        signup: async (req, res, next) => {
            const { name, email, password } = req.body;
            console.log(req.body);
            console.log(name, email, password);
            const hashedPassword = await utils.auth.hashPassword(password);

            try {
                const newUser = await User.create({
                    name,
                    email,
                    password: hashedPassword
                });

                const user = await User.findOne({ email }).lean();
                const token = utils.jwt.createToken({ id: user._id });

                res.cookie(authCookieName, token).send(user);
            } catch (e) {
                console.error(e);
                next();
            }
        },

        login: async (req, res, next) => {
            const { email, password } = req.body;
            console.log(req.body);

            try {
                const status = await utils.auth.checkPassword(email, password);

                if (!status) {
                    res.status(401).send('Invalid username or password!');
                }

                const user = await User.findOne({ email }).lean();
                const token = utils.jwt.createToken({ id: user._id });

                res.cookie(authCookieName, token).send(user);
            } catch (e) {
                console.error(e);
                next();
            }
        },

        verifyLogin: (req, res, next) => {
            console.log(req.headers);
            const token = req.cookie.authCookieName || '';

            Promise.all([
                utils.jwt.verifyToken(token)
            ])
                .then(([data]) => {

                    User.findById(data.id)
                        .then((user) => {
                            return res.send({
                                status: true,
                                user
                            })
                        });
                })
                .catch(err => {
                    if (['token expired', 'jwt must be provided'].includes(err.message)) {
                        res.status(401).send('UNAUTHORIZED!');
                        return;
                    }

                    res.send({
                        status: false
                    })

                    next();
                })
        },

        logout: async (req, res, next) => {
            try {
                res.clearCookie(authCookieName).send('Logout Successful!');
            } catch (e) {
                console.error(e);
                next();
            }
        }
    }
};
 

Ответ №1:

isLogged $ является наблюдаемым.

Вы не можете писать в navigation.component.html <li *ngIf="!isLogged$" class="login">

Пожалуйста, попробуйте <li *ngIf="!(isLogged$ | async)" class="login">

Асинхронный канал подписывается на Наблюдаемое или обещание и возвращает последнее значение, которое он выдал.