获得循环依赖错误(Getting a cyclic dependency error)

2019-10-30 04:46发布

我想利用的角度,智威汤逊 ,但我得到了跟随循环依赖错误:

Cannot instantiate cyclic dependency! InjectionToken_JWT_OPTIONS
  at NgModuleProviderAnalyzer.parse (compiler.js:19550)
    at NgModuleCompiler.compile (compiler.js:20139)
    at JitCompiler._compileModule (compiler.js:34437)
    at eval (compiler.js:34368)
    at Object.then (compiler.js:474)
    at JitCompiler._compileModuleAndComponents (compiler.js:34366)
    at JitCompiler.compileModuleAsync (compiler.js:34260)
    at CompilerImpl.compileModuleAsync (platform-browser-dynamic.js:239)
    at PlatformRef.bootstrapModule (core.js:5567)
    at eval (main.ts:13)

在我的第一个演示角5的应用,这里是我的设置:

import {NgModule} from '@angular/core';
import {HttpClientModule} from '@angular/common/http';
import {JwtModule, JWT_OPTIONS} from '@auth0/angular-jwt';

import {KeycloakService} from './keycloak.service';

// See https://github.com/auth0/angular2-jwt

export function jwtOptionsFactory(keycloakService) {
  return {
    whitelistedDomains: ['localhost:3001'],
    blacklistedRoutes: ['localhost:3001/auth/'],
    tokenGetter: () => {
      return keycloakService.getJwtTokenFromLocalStorage();
    }
  };
}

@NgModule({
  imports: [
    HttpClientModule,
    JwtModule.forRoot({
      jwtOptionsProvider: {
        provide: JWT_OPTIONS,
        useFactory: jwtOptionsFactory,
        deps: [KeycloakService]
      }
    })
  ],
  providers: [
    KeycloakService
  ]
})
export class AuthModule {}

有一个空DEPS:属性删除问题。 当然,没有被注入的服务是没有解决办法。

我的服务是:

import {Injectable} from '@angular/core';
import {environment} from '../environments/environment';
import {Observable} from 'rxjs';
import {JwtHelperService} from '@auth0/angular-jwt';
import {HttpClient, HttpHeaders} from '@angular/common/http';

declare let Keycloak: any;

const JWT_TOKEN_NAME: string = 'token';

@Injectable()
export class KeycloakService {

  static auth: any = {};

  constructor(private httpClient: HttpClient, private jwtHelperService: JwtHelperService) {}

  static init(): Promise<any> {
    const keycloakAuth: any = Keycloak({
      url: environment.KEYCLOAK_URL,
      realm: environment.KEYCLOAK_REALM,
      clientId: environment.KEYCLOAK_CLIENTID,
      'ssl-required': 'external',
      'public-client': true
    });

    KeycloakService.auth.loggedIn = false;

    return new Promise((resolve, reject) => {
      keycloakAuth.init({onLoad: 'check-sso'})
        .success(() => {
          console.log('The keycloak client has been initiated successfully');
          KeycloakService.auth.loggedIn = true;
          KeycloakService.auth.authz = keycloakAuth;
          KeycloakService.auth.logoutUrl = environment.KEYCLOAK_URL
            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
            + document.baseURI;
          resolve();
        })
        .error(() => {
          reject();
        });
    });
  }

  static hasRole(role: string): boolean {
    return KeycloakService.auth.authz.tokenParsed.realm_access.roles.indexOf(role) > -1;
  }

  static getUsername(): string {
    return KeycloakService.auth.authz.tokenParsed.preferred_username;
  }

  static getFullName(): string {
    return KeycloakService.auth.authz.tokenParsed.name;
  }

  public login(ussername: string, password: string): Observable<any> {
    console.log('Sending the login credentials to obtain a token');
    const credentials = {username: ussername, password: password};
    const url: string = environment.KEYCLOAK_URL + '/realms/' + environment.KEYCLOAK_REALM
      + '/protocol/openid-connect/token/generate-token';
    return this.httpClient.post(url, credentials);
  }

  public logout(): void {
    KeycloakService.auth.loggedIn = false;
    KeycloakService.auth.authz = null;
    window.location.href = KeycloakService.auth.logoutUrl;
  }

  public getToken(): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      if (KeycloakService.auth.authz && KeycloakService.auth.authz.token) {
        KeycloakService.auth.authz
          .updateToken(5) // Refresh the token if it will expire in n seconds or less
          .success(() => {
            resolve(<string>KeycloakService.auth.authz.token);
          })
          .error(() => {
            reject('Failed to refresh the auth token');
          });
      } else {
        reject('The auth token could not be retrieved because the user was not logged in');
      }
    });
  }

  public isAuthenticated(): boolean {
    const token = this.getJwtTokenFromLocalStorage();
    return (token && !this.jwtHelperService.isTokenExpired(token));
  }

  public getTokenExpirationDate() {
    const token = this.getJwtTokenFromLocalStorage();
    return this.jwtHelperService.getTokenExpirationDate(token);
  }

  public getDecodedToken() {
    const token = this.getJwtTokenFromLocalStorage();
    return this.jwtHelperService.decodeToken(token);
  }

  public getJwtTokenFromLocalStorage(): string {
    return localStorage.getItem(JWT_TOKEN_NAME);
  }

  public setJwtTokenToLocalStorage(token: string): void {
    localStorage.setItem(JWT_TOKEN_NAME, token);
  }

  public getJwtTokenName(): string {
    return JWT_TOKEN_NAME;
  }

}

我所有的依赖关系是:

"@angular/animations": "^5.2.0",
"@angular/common": "^5.2.0",
"@angular/compiler": "^5.2.0",
"@angular/core": "^5.2.0",
"@angular/forms": "^5.2.0",
"@angular/http": "^5.2.0",
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
"@auth0/angular-jwt": "^1.0.0",
"angular-in-memory-web-api": "^0.5.3",
"core-js": "^2.4.1",
"jwt-decode": "^2.2.0",
"keycloak-js": "^3.4.3",
"npm": "^5.6.0",
"rxjs": "^5.5.6",
"zone.js": "^0.8.19"

更新:我来拆分业务分成两个服务,一个KeycloakService对付Keycloak服务器和AuthService排序它封装的,从而具有更小尺寸的服务。 问题仍然虽然,我不得不去为大卫的解决方案,他所提到的解决方法。 而我的新AuthService具有下面的构造:

@Injectable()
export class AuthService {

  //  constructor(private jwtHelperService: JwtHelperService) {} TODO
  jwtHelperService: JwtHelperService;
  constructor(private injector: Injector) {
    let jwtHelperService = this.injector.get(JwtHelperService);
  }

Answer 1:

作为一种变通方法(它不是真正的理想,虽然),你可以直接注射进样器在你的KeycloakService

export class KeycloakService {

  static auth: any = {};

  constructor(private injector: Injector) {}

然后,当你需要访问HttpClientJwtHelperService ,那么你可以拨打决心在您的服务(而不是在构造函数中!)

let httpClient = this.injector.get<HttpClient>(HttpClient);

编辑:从对这个问题的评论它看起来像它的JwtHelperService导致了问题,所以你只能onject InjectorHttpClient在服务的构造和解决JwtHelperService需要时



文章来源: Getting a cyclic dependency error