如何在 Angular 5 中重定向到 401 响应的登录页面?

How can I redirect to login page on 401 response in Angular 5?

我正在使用 OAuth2 隐式流程开发 Angular 5 应用程序。

我有执行 HTTP 调用的服务,以下是我的服务示例:

@Injectable()
export class MyService {

  constructor(public http: HttpClient) { }

  public getAll(): Observable<Persona[]> {
    return this.http.get<Persona[]>("http://mywebservice/persone");
  }
}

我正在使用拦截器进行授权并添加自定义属性。按照我的身份验证拦截器:

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor() {

  }
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let accessToken = sessionStorage.getItem("access_token");
    if(accessToken)
    {
        request = request.clone({
        setHeaders: {
            Authorization: `Bearer ${accessToken}`
        }
        });
    }

    return next.handle(request);
  }
}

下面是我使用服务的方式:

public myMethod() {
    this.myService.getAll().subscribe(
        result => {
            console.log(result);
        }, error => {
            // I don't want add redirection there...
            console.error(error);
        });
}

现在我需要的是,当任何 HTTP 调用收到 401 结果时,应用程序将用户重定向到登录页面。

如何在不重复代码的情况下获得这个结果?

非常感谢

将错误处理附加到通用请求处理程序:

return next.handle(request).catch(err => {
    if (err.status === 401) {
         // Redirect here
    }
}

您可以直接在拦截器中导入路由器,但正确的方法是创建一个验证服务或类似的导入路由器并调用它来进行重定向

我解决了更改拦截器的问题,如下所示:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor() {

  }
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let accessToken = sessionStorage.getItem("access_token");
    if(accessToken)
    {
        request = request.clone({
        setHeaders: {
            Authorization: `Bearer ${accessToken}`
        }
        });
    }

    return next.handle(request).do((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        if (err.status === 401) {
            this.router.navigate(['login']);
        }
      }
    });
  }
}

我在那里找到了解决方案:https://medium.com/@ryanchenkie_40935/angular-authentication-using-the-http-client-and-http-interceptors-2f9d1540eb8

只是为了支持新读者,请注意在 angular 7 中你应该使用 pipe() 而不是 do() 或 catch():

return next.handle(request).pipe(catchError(err => {
    if (err.status === 401) {
        MyComponent.logout();
    }
    const error = err.error.message || err.statusText;
        return throwError(error);
}));

这里是 Angular 11

import {
  HttpErrorResponse,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable, throwError } from "rxjs";
import { catchError, map } from "rxjs/operators";
import HttpStatusCode from "src/app/models/enums/HttpStatusCode";
import { AuthenticationService } from "./authentication.service";

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private authenticationService: AuthenticationService) {}

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      map((event: HttpEvent<any>) => {
        return event;
      }),
      catchError(
        (
          httpErrorResponse: HttpErrorResponse,
          _: Observable<HttpEvent<any>>
        ) => {
          if (httpErrorResponse.status === HttpStatusCode.UNAUTHORIZED) {
            this.authenticationService.redirectToLogin();
          }
          return throwError(httpErrorResponse);
        }
      )
    );
  }
}

AuthenticationService中声明的如下方法

public redirectToLogin(path: string, queryParams: any) {
    this.router.navigate([path], {
        queryParams,
        queryParamsHandling: "merge",
    });
}