0

我的身份验证服务有问题。如果我在构造函数中发出 http 请求,它会被调用 259 次。如果我删除 http 调用,它会被调用一次。我使用共享模块来提供该服务的唯一实例。

角度版本:4.4.4

控制台打印

这是我的共享模块:

export const providers = [
  AuthService,
  DataStorageService,
];

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    HttpClientModule,
    ReactiveFormsModule,
    InfiniteScrollModule,
    TruncateModule
  ],
  declarations: [
    FooterComponent,
    PhotoListComponent,
    GalleryListComponent,
     ],
  exports: [
    FooterComponent,
    PhotoListComponent,
    GalleryListComponent,
    InfiniteScrollModule,

  ],
  providers: [
    
    ]})

export class SharedModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [...providers]
    };
  }
}

还有我的 AuthService:

@Injectable()
export class AuthService {

  public session: Subject<SessionModel> = new Subject<SessionModel>();
  private cachedSession: SessionModel = new SessionModel(null, null, false);
  private apiUrl = 'http://localhost:8080/Galleo/user/login';


   constructor(private cookieSrv: CookieService,
              private http: HttpClient) {
    console.log('constructor called');
    if (this.cookieSrv.get('system-g-unx-data')) {
      const cook = atob(this.cookieSrv.get('system-g-unx-data')).split('||');
      const username = cook[0];
      const password = cook[1];
      this.login(username, password);
    }
  }

  // login method, call REST API and store cookie into user Browser
  login(username: string, password: string) {

    const user: UserModel = new UserModel();
    user.userName = username;
    user.password = password;

    const headers = new HttpHeaders();
    headers.append('Content-Type', 'application/json');

    this.http.post<UserModel>(this.apiUrl, user, {observe: 'response', headers: headers}).subscribe(
      (response) => {
        console.dir(response);
        this.cachedSession.user = response.body;
        this.cachedSession.token = response.headers.get('Authorization');
        this.cachedSession.isAuthenticated = true;
        this.session.next(this.cachedSession);
        this.cookieSrv.put('system-g-unx-data', btoa(username + '||' + password));
      },
      (error) => {
        console.dir(error);
        this.session.next(null);
      }
    );
   }
  }

谢谢!

编辑:我发现了问题。来自 AuthInterceptor。当我尝试获取授权令牌时,它会启动一个无限循环:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private authService: AuthService;
  constructor(private injector: Injector) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('Intercepted!', req);
    this.authService = this.injector.get(AuthService);

    const request = req.clone({
      setHeaders: {
        Authorization:  `${this.authService.getSession().token}`
      }
    });

    return next.handle(request);

  }
}

现在如何在不使用注入器的情况下恢复 Interceptor 中的 authService?

最终编辑:我想出了如何从我的 authService 获取令牌而不进行无限循环。问题是我用来为每个请求添加令牌到授权标头的 HttpInterceptor。在我的 AuthService 构造函数中,我调用了发出 http 请求的登录方法.. LOOP: INTERCEPTOR => AUTH SERVICE => HTTP CLIENT 并再次 INTERCEPTOR

因此,现在我在拦截器中进行一些检查,例如:

Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private authService: AuthService;
  constructor(private injector: Injector) {  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    // If login method called skip and continue request
    if (req.url.includes('login')) {
      return next.handle(req);
    }

    // If request don't have the Authorization Header, add the token to the header
    if (!req.headers.has('Authorization')) {
      this.authService = this.injector.get(AuthService);
      const request = req.clone({
        setHeaders: {
          Authorization: `${this.authService.getSession().token}`
        }
      });
      return next.handle(request);
    }

    return next.handle(req);
  }

也许可以帮助遇到同样问题的人。PS:喷油器需要在检查后调用

感谢帮助!

4

1 回答 1

1

创建一个 core/core.module.ts 你在 app.module.ts 中导入一次

import { CommonModule } from '@angular/common';
import {
  ModuleWithProviders, NgModule,
  Optional, SkipSelf
} from '@angular/core';


import { AuthGuard } from '../guards/auth.guard';
import { AuthService } from '../services/auth.service';

@NgModule({
  imports: [CommonModule],
  declarations: [],
  exports: [],
  providers: [AuthGuard, AuthService]
})

export class CoreModule {

  constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error(
        'CoreModule is already loaded. Import it in the AppModule only');
    }
  }

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: CoreModule,
      providers: [
        AuthService,
        AuthGuard,
      ]
    };
  }
}

有一个检查以确保它只加载一次。

app.module.ts

import {CoreModule} from './core/core.module';

@NgModule({
  declarations: [
  ],
  imports: [
    CoreModule.forRoot(),
  ],
  providers: [

  ],
  bootstrap: [AppComponent]
})

它在“核心模块” https://angular.io/guide/ngmodule下的文档中被引用为单例

于 2017-10-11T15:34:43.830 回答