DevGang
Авторизоваться

Angular — выход из системы при 401 неавторизованном или 403 запрещенном HTTP-ответе с перехватчиком

Это быстрый пример того, как автоматически выйти из приложения Angular, если HTTP-запрос возвращает ответ 401 Unauthorized или 403 Forbidden.

Приведенные ниже фрагменты кода взяты из руководства по входу в Angular, которое автоматически выходит из системы, если из API возвращается ответ об ошибке 401 или 403. Полное руководство, включая живую демонстрацию кода, см. в разделе Angular 14 — Пример и руководство по регистрации и входу в систему.

Перехватчик ошибок HTTP с выходом из системы на 401 или 403

Путь: /src/app/_helpers/error.interceptor.ts

Перехватчик ошибок перехватывает все ответы HTTP от API, чтобы проверить наличие ошибок. Если есть ответ 401 Unauthorized или 403 Forbidden, пользователь автоматически выходит из приложения, все другие ошибки повторно выдаются вызывающей службе или компоненту.

Он реализован с использованием интерфейса Angular HttpInterceptor, включенного в HttpClientModule. Благодаря реализации интерфейса HttpInterceptor вы можете создать собственный перехватчик для перехвата всех ответов об ошибках от API в одном месте.

Перехватчики HTTP добавляются в конвейер запросов в разделе providers файла app.module.ts.

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

import { AccountService } from '@app/_services';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
    constructor(private accountService: AccountService) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(catchError(err => {
            if ([401, 403].includes(err.status) && this.accountService.userValue) {
                // auto logout if 401 or 403 response returned from api
                this.accountService.logout();
            }

            const error = err.error?.message || err.statusText;
            console.error(err);
            return throwError(() => error);
        }))
    }
}

Служба учетных записей, которая отправляет HTTP-запросы

Path: /src/app/_services/account.service.ts

Служба учетных записей обрабатывает связь между приложением Angular и внутренним API для всего, что связано с учетными записями. Он содержит методы для входа, выхода и регистрации, а также стандартные методы CRUD для получения, изменения и удаления пользовательских данных.

Включим его сюда, чтобы показать примеры HTTP-запросов, отправляемых из Angular в API.

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { environment } from '@environments/environment';
import { User } from '@app/_models';

@Injectable({ providedIn: 'root' })
export class AccountService {
    private userSubject: BehaviorSubject<User | null>;
    public user: Observable<User | null>;

    constructor(
        private router: Router,
        private http: HttpClient
    ) {
        this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('user')!));
        this.user = this.userSubject.asObservable();
    }

    public get userValue() {
        return this.userSubject.value;
    }

    login(username: string, password: string) {
        return this.http.post<User>(`${environment.apiUrl}/users/authenticate`, { username, password })
            .pipe(map(user => {
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('user', JSON.stringify(user));
                this.userSubject.next(user);
                return user;
            }));
    }

    logout() {
        // remove user from local storage and set current user to null
        localStorage.removeItem('user');
        this.userSubject.next(null);
        this.router.navigate(['/account/login']);
    }

    register(user: User) {
        return this.http.post(`${environment.apiUrl}/users/register`, user);
    }

    getAll() {
        return this.http.get<User[]>(`${environment.apiUrl}/users`);
    }

    getById(id: string) {
        return this.http.get<User>(`${environment.apiUrl}/users/${id}`);
    }

    update(id: string, params: any) {
        return this.http.put(`${environment.apiUrl}/users/${id}`, params)
            .pipe(map(x => {
                // update stored user if the logged in user updated their own record
                if (id == this.userValue?.id) {
                    // update local storage
                    const user = { ...this.userValue, ...params };
                    localStorage.setItem('user', JSON.stringify(user));

                    // publish updated user to subscribers
                    this.userSubject.next(user);
                }
                return x;
            }));
    }

    delete(id: string) {
        return this.http.delete(`${environment.apiUrl}/users/${id}`)
            .pipe(map(x => {
                // auto logout if the logged in user deleted their own record
                if (id == this.userValue?.id) {
                    this.logout();
                }
                return x;
            }));
    }
}

Модуль приложения, добавляющий HTTP-перехватчик

Путь: /src/app/app.module.ts

Модуль приложения определяет корневой модуль приложения Angular вместе с метаданными о модуле.

ErrorInterceptor настраивается как перехватчик HTTP для приложения в разделе providers со следующими свойствами:

  • provide: HTTP_INTERCEPTORS - токен внедрения Angular, используемый поставщиком DI, который сопоставляется с массивом перехватчиков HTTP для приложения.
  • useClass: ErrorInterceptor - класс для добавления в массив HTTP_INTERCEPTORS.
  • multi: true - требуется для HTTP_INTERCEPTORS, он настраивает токен внедрения как токен с несколькими поставщиками, представляющий массив значений.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

// used to create fake backend
import { fakeBackendProvider } from './_helpers';

import { AppRoutingModule } from './app-routing.module';
import { JwtInterceptor, ErrorInterceptor } from './_helpers';
import { AppComponent } from './app.component';
import { AlertComponent } from './_components';
import { HomeComponent } from './home';

@NgModule({
    imports: [
        BrowserModule,
        ReactiveFormsModule,
        HttpClientModule,
        AppRoutingModule
    ],
    declarations: [
        AppComponent,
        AlertComponent,
        HomeComponent
    ],
    providers: [
        { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
        { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },

        // provider used to create fake backend
        fakeBackendProvider
    ],
    bootstrap: [AppComponent]
})
export class AppModule { };
#Angular
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться