0

我的 Angular 11 应用程序使用带有隐式流的 oidc-client 。我用警卫保护了我的一条路线(应该只对经过身份验证的用户可用)。当我使用应用程序中的链接导航到受限区域(比如说 http://localhost:4200/restricted-area/)时,它工作得很好。然而,问题是当我尝试“手动”导航到那个页面时(例如在我的浏览器中输入 url),应用程序将我视为没有经过身份验证。当我在“正确”导航后简单地刷新页面时,也会出现同样的问题。有趣的是,在这两种情况下,在重定向到主页后,我都会再次登录。

作为一种解决方法,我正在考虑在 [canActivate] 方法的开头实现从会话存储中额外手动提取令牌,但我希望有更好的方法来解决这个问题。

AuthGuard 实现:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from './shared/services/auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if (this.authService.isAuthenticated()) { return true; }
    alert('Authentication required.');
    this.router.navigate(['/menu'], { queryParams: { redirect: state.url }, replaceUrl: true });
    return false;
  }

}

AuthService 实现如下所示:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { UserManager, UserManagerSettings, User } from 'oidc-client';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthService  {

  private _authNavStatusSource = new BehaviorSubject<boolean>(false);
  authNavStatus$ = this._authNavStatusSource.asObservable();

  private manager = new UserManager(getClientSettings());
  private user: User | null;

  constructor(private http: HttpClient) {
    this.manager.getUser().then(user => {
      this.user = user;
      this._authNavStatusSource.next(this.isAuthenticated());
    });
  }

  login() {
    return this.manager.signinRedirect();
  }

  async completeAuthentication() {
      this.user = await this.manager.signinRedirectCallback();
      this._authNavStatusSource.next(this.isAuthenticated());
  }

  register(userRegistration: any) {
    // return this.http.post(this.configService.authApiURI + '/account', userRegistration).pipe(catchError(this.handleError)); // temporary disabled
  }

  isAuthenticated(): boolean {
    return this.user != null && !this.user.expired;
  }

  get authorizationHeaderValue(): string {
    return `${this.user.token_type} ${this.user.access_token}`;
  }

  get name(): string {
    return this.user != null ? this.user.profile.name : '';
  }

  async signout() {
    await this.manager.signoutRedirect();
  }
}

export function getClientSettings(): UserManagerSettings {
  return {
      authority: 'http://xxxxxxxxxx',
      client_id: 'xxxxxxxxxxx',
      redirect_uri: 'http://xxxxxxxxxxx/auth-callback',
      post_logout_redirect_uri: 'http://xxxxxxxxxxx',
      response_type:"id_token token",
      scope:"xxxxxxxxxxxxxxxxxxxxxxxxxx",
      filterProtocolClaims: true,
      loadUserInfo: true,
      automaticSilentRenew: true,
      silent_redirect_uri: 'xxxxxxxxxxxxxxxxxxxxxxxxx'
  };
}

路由(应用程序):

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthCallbackComponent } from './auth-callback/auth-callback.component';
import { AuthGuard } from './auth.guard';
import { MenuComponent } from './menu/menu.component';

const routes: Routes = [
  { path: 'menu', component: MenuComponent },
  { path: 'auth-callback', component: AuthCallbackComponent },
  { path: 'suppliers', redirectTo: 'suppliers', pathMatch: 'full', canActivate: [AuthGuard] },
  { path: '**', redirectTo: '/menu', pathMatch: 'full' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

路由(父模块):

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '../auth.guard';
import { SupplierContactFormComponent } from './supplier-contact-form/supplier-contact-form.component';
import { SupplierFormComponent } from './supplier-form/supplier-form.component';
import { SupplierListComponent } from './supplier-list/supplier-list.component';
import { SupplierViewComponent } from './supplier-view/supplier-view.component';
import { SupplierResolver } from './supplier.resolver';
import { SupplierComponent } from './supplier/supplier.component';

const routes: Routes = [
  {
    path: 'suppliers', canActivate: [AuthGuard], children: [
      { path: '', component: SupplierListComponent },
      { path: ':supplierId', component: SupplierComponent, resolve: { supplier: SupplierResolver }, children: [
        { path: '', pathMatch: 'full', component: SupplierViewComponent },
        { path: 'edit', component: SupplierFormComponent},
        { path: 'create-contact', component: SupplierContactFormComponent },
        { path: 'edit-contact/:contactId', component: SupplierContactFormComponent },
      ] },
    ]
  },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class SupplierRoutingModule { }
4

0 回答 0