强制 Angular 应用程序在 session 过期时重定向
Force Angular app to redirect when session expired
我有一个 Angular 应用需要 OIDC 服务的 session 授权。使用 normal/happy 路径,一个单独的 NodeJS/Express 应用程序检查 session 授权并重定向到 OIDC authorization/authentication 服务并附加相关的 headers。如果一切顺利,中间件将路由到 Angular 应用程序。
不过,Angular 应用程序有时会使用过期的令牌运行。 Angular 应用程序获取用户名,此时我可以检查是否过期。但是,如果它已过期,我需要 Angular 方法通过 re-routing 整个 Angular 应用程序到相关中间件页面来对错误情况做出反应。因为指示器将转到嵌套在应用程序中的组件,所以我不知道如何让这个小组件重定向 bigger/encompassing 应用程序。
我不是 Angular 人,所以我什至不知道要查找 Angular 的哪一部分。由于我缺乏知识,我包含了可能相关或不相关的源文件。
header.component.ts 是它获取用户名的地方,可能 return 一个错误的令牌指标
import { Component, OnInit } from '@angular/core';
import { ProfileService } from '../../../core/services/profile.service';
@Component({
selector: 'header-comp',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
userName: string = 'No Session';
constructor(private profileService: ProfileService) { }
ngOnInit() {
this.onDisplayUserLogged();
}
onDisplayUserLogged() {
this.profileService.getUsername().subscribe(data => {
this.userName = 'Welcome: ' + data;
});
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { APP_BASE_HREF } from '@angular/common';
import { Router } from '@angular/router';
//Services
import { ProfileService } from './core/services/profile.service';
import { FinanceService } from './core/services/finance.service';
import { CmasService } from './core/services/cmas.service';
import { SoftlayerService } from './core/services/softlayer.service';
import { DashboardService } from './core/services/dashboard.service';
import { LowDollarExceptionService } from './core/services/lowDollarException.service';
//Components
import { AppComponent } from './app.component';
import { CmasComponent } from './modules/cmas/cmas.component';
import { SoftlayerComponent } from './modules/softlayer/softlayer.component';
import { FinanceComponent } from './modules/finance/finance.component';
import { ErrorComponent } from './modules/error/error/error.component';
import { LowDollarExceptionComponent } from './modules/lowDollarException/lowDollarException.component'
import { MenuComponent } from './shared/layout/menu/menu.component';
import { BasicComponent } from './shared/modals/basic/basic.component';
import { HeaderComponent } from './shared/layout/header/header.component';
import { PreProcessedPipe } from './shared/components/file-listing/file-listing.component';
import { ProcessedPipe } from './shared/components/softlayer-file-list/softlayer-file-list.component';
//Routing
import { AppRoutingModule } from './app-routing.module';
//Libs
import { AuthInterceptor } from 'auth-lib';
import { TermsComponent } from './modules/terms/terms.component';
import { FileListingComponent } from './shared/components/file-listing/file-listing.component';
import { ConfirmCancelComponent } from './shared/modals/confirm-cancel/confirm-cancel.component';
import { ErrorDisplayComponent } from './shared/components/error-display/error-display.component';
import { AboutComponent } from './modules/about/about.component';
import { ResultsComponent } from './modules/cmas/results/results.component';
import { SoftlayerFileListComponent } from './shared/components/softlayer-file-list/softlayer-file-list.component';
import { DashboardComponent } from './modules/dashboard/dashboard.component';
import { ReviewResultsComponent } from './modules/softlayer/review-results/review-results.component';
import { InvoiceDetailsComponent } from './modules/dashboard/invoice-details/invoice-details.component';
import { FormsModule } from '@angular/forms';
import { LowDollarNewRecordComponent } from './modules/lowDollarException/lowDollarNewRecord.component';
@NgModule({
declarations: [
AppComponent,
CmasComponent,
FinanceComponent,
ErrorComponent,
MenuComponent,
BasicComponent,
HeaderComponent,
TermsComponent,
FileListingComponent,
PreProcessedPipe,
ProcessedPipe,
ConfirmCancelComponent,
ErrorDisplayComponent,
AboutComponent,
ResultsComponent,
SoftlayerComponent,
SoftlayerFileListComponent,
DashboardComponent,
ReviewResultsComponent,
InvoiceDetailsComponent,
LowDollarExceptionComponent,
LowDollarNewRecordComponent
],
imports: [BrowserModule, HttpClientModule, AppRoutingModule, FormsModule],
providers: [
ProfileService,
FinanceService,
CmasService,
SoftlayerService,
DashboardService,
LowDollarExceptionService,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
deps: [Router],
multi: true,
},
{ provide: APP_BASE_HREF, useValue: '/sprint-cost-recovery' },
],
bootstrap: [AppComponent],
})
export class AppModule {}
app.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import listadeTerms from '../assets/config/properties.json';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
constructor() {}
ngOnInit() {
this.openOverlay();
}
openOverlay() {
var sheet = document.createElement('style');
sheet.innerHTML =
'.ds-full-width {visibility: hidden;} .usabilla_live_button_container{visibility: hidden;}';
document.body.appendChild(sheet);
if (document.getElementById('termsDialog')) {
var overlayElement = document.querySelector('#termsDialog');
overlayElement.classList.add('ds-open');
document
.querySelector('#termsDialogCloseBtn')
.addEventListener('click', load);
}
function load() {
var div = document.getElementById('termsDialog');
sheet.innerHTML = '.usabilla_live_button_container{visibility: true;}';
var parent = div.parentElement;
parent.removeChild(div);
var node = sheet.parentNode;
node.removeChild(sheet);
}
}
}
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
// Components
import { CmasComponent } from './modules/cmas/cmas.component';
import { FinanceComponent } from './modules/finance/finance.component';
import { ErrorComponent } from './modules/error/error/error.component';
import { AboutComponent } from './modules/about/about.component';
import { SoftlayerComponent } from './modules/softlayer/softlayer.component';
import { DashboardComponent } from './modules/dashboard/dashboard.component';
import { LowDollarExceptionComponent } from './modules/lowDollarException/lowDollarException.component';
import { LowDollarNewRecordComponent } from './modules/lowDollarException/lowDollarNewRecord.component';
const appRoutes: Routes = [
{ path: 'finance', component: FinanceComponent },
{ path: 'cmas-process', component: CmasComponent },
{ path: 'about', component: AboutComponent },
{ path: 'softlayer-process', component: SoftlayerComponent },
{ path: 'cost-dashboard', component: DashboardComponent },
{ path: 'low-dollar', component: LowDollarExceptionComponent },
{ path: 'low-dollar/create', component: LowDollarNewRecordComponent },
{ path: 'error/auth', component: ErrorComponent, data: { forbidden: true } },
{ path: '', redirectTo: '/finance', pathMatch: 'full' },
{
path: 'error/badgateway',
component: ErrorComponent,
data: { badgateway: true },
},
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
在 Angular 中实现此目的的方法是通过 Route Guards。在高层次上,它是这样的:
创建 route guards。它 returns 真或假取决于它检查的条件。
在需要校验的路由中添加canActivate参数,例如:
const appRoutes: Routes = [
{ path: 'finance', component: FinanceComponent, canActivate: [AuthGuard] },
{ path: 'cmas-process', component: CmasComponent, canActivate: [AuthGuard] },
- 如果用户未通过身份验证,则在路由守卫中指定重定向(例如到登录页面):
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivateChild {
constructor(
private authService: AuthService,
private logger: NGXLogger,
private router: Router
) {}
canActivateChild(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> {
return this.authService.isLoggedIn().pipe(
map(isLoggedIn => {
if (!isLoggedIn) {
return this.router.parseUrl('/login');
}
return true;
})
);
}
}
我有一个 Angular 应用需要 OIDC 服务的 session 授权。使用 normal/happy 路径,一个单独的 NodeJS/Express 应用程序检查 session 授权并重定向到 OIDC authorization/authentication 服务并附加相关的 headers。如果一切顺利,中间件将路由到 Angular 应用程序。
不过,Angular 应用程序有时会使用过期的令牌运行。 Angular 应用程序获取用户名,此时我可以检查是否过期。但是,如果它已过期,我需要 Angular 方法通过 re-routing 整个 Angular 应用程序到相关中间件页面来对错误情况做出反应。因为指示器将转到嵌套在应用程序中的组件,所以我不知道如何让这个小组件重定向 bigger/encompassing 应用程序。
我不是 Angular 人,所以我什至不知道要查找 Angular 的哪一部分。由于我缺乏知识,我包含了可能相关或不相关的源文件。
header.component.ts 是它获取用户名的地方,可能 return 一个错误的令牌指标
import { Component, OnInit } from '@angular/core';
import { ProfileService } from '../../../core/services/profile.service';
@Component({
selector: 'header-comp',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
userName: string = 'No Session';
constructor(private profileService: ProfileService) { }
ngOnInit() {
this.onDisplayUserLogged();
}
onDisplayUserLogged() {
this.profileService.getUsername().subscribe(data => {
this.userName = 'Welcome: ' + data;
});
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { APP_BASE_HREF } from '@angular/common';
import { Router } from '@angular/router';
//Services
import { ProfileService } from './core/services/profile.service';
import { FinanceService } from './core/services/finance.service';
import { CmasService } from './core/services/cmas.service';
import { SoftlayerService } from './core/services/softlayer.service';
import { DashboardService } from './core/services/dashboard.service';
import { LowDollarExceptionService } from './core/services/lowDollarException.service';
//Components
import { AppComponent } from './app.component';
import { CmasComponent } from './modules/cmas/cmas.component';
import { SoftlayerComponent } from './modules/softlayer/softlayer.component';
import { FinanceComponent } from './modules/finance/finance.component';
import { ErrorComponent } from './modules/error/error/error.component';
import { LowDollarExceptionComponent } from './modules/lowDollarException/lowDollarException.component'
import { MenuComponent } from './shared/layout/menu/menu.component';
import { BasicComponent } from './shared/modals/basic/basic.component';
import { HeaderComponent } from './shared/layout/header/header.component';
import { PreProcessedPipe } from './shared/components/file-listing/file-listing.component';
import { ProcessedPipe } from './shared/components/softlayer-file-list/softlayer-file-list.component';
//Routing
import { AppRoutingModule } from './app-routing.module';
//Libs
import { AuthInterceptor } from 'auth-lib';
import { TermsComponent } from './modules/terms/terms.component';
import { FileListingComponent } from './shared/components/file-listing/file-listing.component';
import { ConfirmCancelComponent } from './shared/modals/confirm-cancel/confirm-cancel.component';
import { ErrorDisplayComponent } from './shared/components/error-display/error-display.component';
import { AboutComponent } from './modules/about/about.component';
import { ResultsComponent } from './modules/cmas/results/results.component';
import { SoftlayerFileListComponent } from './shared/components/softlayer-file-list/softlayer-file-list.component';
import { DashboardComponent } from './modules/dashboard/dashboard.component';
import { ReviewResultsComponent } from './modules/softlayer/review-results/review-results.component';
import { InvoiceDetailsComponent } from './modules/dashboard/invoice-details/invoice-details.component';
import { FormsModule } from '@angular/forms';
import { LowDollarNewRecordComponent } from './modules/lowDollarException/lowDollarNewRecord.component';
@NgModule({
declarations: [
AppComponent,
CmasComponent,
FinanceComponent,
ErrorComponent,
MenuComponent,
BasicComponent,
HeaderComponent,
TermsComponent,
FileListingComponent,
PreProcessedPipe,
ProcessedPipe,
ConfirmCancelComponent,
ErrorDisplayComponent,
AboutComponent,
ResultsComponent,
SoftlayerComponent,
SoftlayerFileListComponent,
DashboardComponent,
ReviewResultsComponent,
InvoiceDetailsComponent,
LowDollarExceptionComponent,
LowDollarNewRecordComponent
],
imports: [BrowserModule, HttpClientModule, AppRoutingModule, FormsModule],
providers: [
ProfileService,
FinanceService,
CmasService,
SoftlayerService,
DashboardService,
LowDollarExceptionService,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
deps: [Router],
multi: true,
},
{ provide: APP_BASE_HREF, useValue: '/sprint-cost-recovery' },
],
bootstrap: [AppComponent],
})
export class AppModule {}
app.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import listadeTerms from '../assets/config/properties.json';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
constructor() {}
ngOnInit() {
this.openOverlay();
}
openOverlay() {
var sheet = document.createElement('style');
sheet.innerHTML =
'.ds-full-width {visibility: hidden;} .usabilla_live_button_container{visibility: hidden;}';
document.body.appendChild(sheet);
if (document.getElementById('termsDialog')) {
var overlayElement = document.querySelector('#termsDialog');
overlayElement.classList.add('ds-open');
document
.querySelector('#termsDialogCloseBtn')
.addEventListener('click', load);
}
function load() {
var div = document.getElementById('termsDialog');
sheet.innerHTML = '.usabilla_live_button_container{visibility: true;}';
var parent = div.parentElement;
parent.removeChild(div);
var node = sheet.parentNode;
node.removeChild(sheet);
}
}
}
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
// Components
import { CmasComponent } from './modules/cmas/cmas.component';
import { FinanceComponent } from './modules/finance/finance.component';
import { ErrorComponent } from './modules/error/error/error.component';
import { AboutComponent } from './modules/about/about.component';
import { SoftlayerComponent } from './modules/softlayer/softlayer.component';
import { DashboardComponent } from './modules/dashboard/dashboard.component';
import { LowDollarExceptionComponent } from './modules/lowDollarException/lowDollarException.component';
import { LowDollarNewRecordComponent } from './modules/lowDollarException/lowDollarNewRecord.component';
const appRoutes: Routes = [
{ path: 'finance', component: FinanceComponent },
{ path: 'cmas-process', component: CmasComponent },
{ path: 'about', component: AboutComponent },
{ path: 'softlayer-process', component: SoftlayerComponent },
{ path: 'cost-dashboard', component: DashboardComponent },
{ path: 'low-dollar', component: LowDollarExceptionComponent },
{ path: 'low-dollar/create', component: LowDollarNewRecordComponent },
{ path: 'error/auth', component: ErrorComponent, data: { forbidden: true } },
{ path: '', redirectTo: '/finance', pathMatch: 'full' },
{
path: 'error/badgateway',
component: ErrorComponent,
data: { badgateway: true },
},
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
在 Angular 中实现此目的的方法是通过 Route Guards。在高层次上,它是这样的:
创建 route guards。它 returns 真或假取决于它检查的条件。
在需要校验的路由中添加canActivate参数,例如:
const appRoutes: Routes = [
{ path: 'finance', component: FinanceComponent, canActivate: [AuthGuard] },
{ path: 'cmas-process', component: CmasComponent, canActivate: [AuthGuard] },
- 如果用户未通过身份验证,则在路由守卫中指定重定向(例如到登录页面):
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivateChild {
constructor(
private authService: AuthService,
private logger: NGXLogger,
private router: Router
) {}
canActivateChild(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> {
return this.authService.isLoggedIn().pipe(
map(isLoggedIn => {
if (!isLoggedIn) {
return this.router.parseUrl('/login');
}
return true;
})
);
}
}