我有一个 Jmeter 板,您只能通过登录页面访问。我已经创建了一个导入到应用程序主模块中的登录组件和一个用于 Jmeter 板本身的延迟加载模块。
我已经为 Jmeter 板的路由创建了一个拦截器,以便在登录后使用令牌设置头部,并将其导入到这个延迟加载模块的提供程序中。但是,它也会拦截登录路由,尽管它是在 Jmeter 板模块中配置的,而不是在主模块中。
因此,如果我在登录时从后端得到一个错误(例如401 - Wrong credentials),它会显示来自拦截器的吐司错误。
app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { LoginComponent } from "./components/login/login.component";
import { MaterialModule } from "./material/material.module";
import { ReactiveFormsModule } from "@angular/forms";
import { HttpClientModule } from "@angular/common/http";
import { ToastrModule } from "ngx-toastr";
@NgModule({
declarations: [AppComponent, LoginComponent],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MaterialModule,
ReactiveFormsModule,
HttpClientModule,
ToastrModule.forRoot()
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
app-routing。module.ts
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { LoginComponent } from "./components/login/login.component";
import { AuthGuard } from "./guards/auth.guard";
const routes: Routes = [
{ path: "login", component: LoginComponent },
{
path: "dashboard",
loadChildren: () =>
import("./components/dashboard/dashboard.module").then(
(m) => m.DashboardModule
),
canActivate: [AuthGuard],
},
{ path: "", redirectTo: "/login", pathMatch: "full" },
{ path: "**", redirectTo: "/dashboard", pathMatch: "full" },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
dashboard.module.ts
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { PageNotFoundComponent } from "./components/page-not-found/page-not-found.component";
import { DashboardRoutingModule } from "./dashboard-routing.module";
import { ForbiddenComponent } from "./components/forbidden/forbidden.component";
import { SidenavComponent } from "./components/sidenav/sidenav.component";
import { SidenavService } from "./services/sidenav.service";
import { HTTP_INTERCEPTORS } from "@angular/common/http";
import { ToastrModule } from "ngx-toastr";
import { TokenInterceptor } from "src/app/interceptors/token.interceptor";
import { DashboardComponent } from "./dashboard.component";
import { ToolbarComponent } from "./components/toolbar/toolbar.component";
@NgModule({
declarations: [
DashboardComponent,
PageNotFoundComponent,
ForbiddenComponent,
ToolbarComponent,
SidenavComponent,
],
imports: [CommonModule, DashboardRoutingModule, ToastrModule.forRoot()],
providers: [
SidenavService,
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true,
},
],
})
export class DashboardModule {}
** Jmeter 板路由。module.ts**
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
import { DashboardComponent } from './dashboard.component';
const routes: Routes = [
{
path: '',
component: DashboardComponent,
children: [
{
path: 'notifications',
loadChildren: () =>
import('./components/notifications/notifications.module').then(
(m) => m.NotificationsModule
)
},
],
},
{ path: '**', component: PageNotFoundComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DashboardRoutingModule {}
token.interceptor.ts
import { Injectable } from "@angular/core";
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse,
} from "@angular/common/http";
import { Observable, catchError, throwError } from "rxjs";
import { AuthService } from "../services/auth.service";
import { ToastrService } from "ngx-toastr";
import { Router } from "@angular/router";
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(
private auth: AuthService,
private toastr: ToastrService,
private router: Router
) {}
intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<unknown>> {
const token = this.auth.accessToken;
if (!!token) {
request = request.clone({
setHeaders: { Authorization: `Bearer ${token}` },
});
}
return next.handle(request).pipe(
catchError((err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
this.toastr.warning(
"Try to login again",
"Session has expired"
);
this.router.navigate(["login"]);
}
}
return throwError((err: any) => new Error(err));
})
);
}
}
1条答案
按热度按时间ha5z0ras1#
拦截器在每个请求上运行。它们不绑定到路由或特定的模块,即使您在特定的模块中声明它。当你的
DashboardModule
被延迟加载后,它会拦截你发送的每个请求。如果您希望行为仅绑定到特定的路由,则应该使用路由防护。但我认为在您的情况下(如果我正确理解了所需的行为),您可以更改拦截器逻辑,使其仅处理具有Authorization头的请求,并将其他请求直接转发到下一个处理程序。我建议像这样改变拦截器的逻辑:
因此,不同之处在于,在这种情况下,401错误处理不会添加到没有令牌的请求(如登录请求)中,而是仅添加到具有添加了承载令牌的Authorization报头的请求中。
防止未经授权的请求从
DashboardModule
中发送到服务器应该使用路由保护来完成,但看起来这部分已经包含在AuthGuard
中了。**注意:**我也改变了
throwError
逻辑,通过像你一样将错误 Package 在另一个Error
类中,你可能会意外地破坏其他拦截器或应用程序逻辑,期望HttpErrorResponse
类型的错误。