1

我正在设置蓝/绿部署,并尝试redirectUri根据用户正在查看的当前 url 更改以下内容 ( redirectUri: this.router.url + '/callback',)。我收到Uncaught TypeError: Cannot read property 'router' of undefined以下配置。

import { APP_BASE_HREF } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { CoreModule } from './@core/core.module';
import { AuthGuard } from './auth-guard.service';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { ThemeModule } from './@theme/theme.module';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NbOAuth2AuthStrategy,
        NbAuthModule,
        NbOAuth2ResponseType,
        NbOAuth2GrantType,
        NbAuthOAuth2Token,
       } from '@nebular/auth';
import { OAuth2LoginComponent } from './auth/oauth2-login.component';
import { OAuth2CallbackComponent } from './auth/oauth2-callback.component';
import { environment } from '../environments/environment';
import { Router } from '@angular/router';

@NgModule({
  declarations: [AppComponent, OAuth2LoginComponent, OAuth2CallbackComponent ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    NgbModule.forRoot(),
    ThemeModule.forRoot(),
    CoreModule.forRoot(),
    NbAuthModule.forRoot({
      forms: {},
      strategies: [
        NbOAuth2AuthStrategy.setup({
          baseEndpoint: environment.authUrl,
          name: 'cognito',
          clientId: environment.clientId,
          authorize: {
            endpoint: '/oauth2/authorize',
            responseType: NbOAuth2ResponseType.CODE,
            scope: 'aws.cognito.signin.user.admin',
            redirectUri: this.router.url + '/callback',
          },
          redirect: {
            success: '/pages/dashboard',
          },
          token: {
            endpoint: '/oauth2/token',
            grantType: NbOAuth2GrantType.AUTHORIZATION_CODE,
            class: NbAuthOAuth2Token,
            redirectUri: this.router.url + '/callback',
          },
          refresh: {
            endpoint: 'refresh-token',
            grantType: NbOAuth2GrantType.REFRESH_TOKEN,
          },
        }),
       ],
    }),
    AppRoutingModule,
  ],
  bootstrap: [AppComponent],
  providers: [
    AuthGuard,
    { provide: APP_BASE_HREF, useValue: '/' },
  ],
})
export class AppModule {
  constructor(private router: Router) {}
}

我也尝试过使用redirectUri: window.location.origin + '/callback'which 在本地工作,但在为生产而构建时为空。

4

4 回答 4

2

请注意,类级别的装饰器在创建类的任何实例之前应用于构造函数。所以路由器属性对装饰器不可用。在示例this.router.url + '/callback'中是指全局this而不是,奇怪的是没有编译错误。

关于window.location,在aotprod 构建的默认编译模式下,装饰器中的表达式在编译时由 Angular 编译器执行,因此window.location在那里不可用。看看这个 GitHub 问题:AOT replaces window.location object to null

作为一种解决方法,您可以动态初始化NbOAuth2AuthStrategy,例如:

@NgModule({
  imports: [
    ...
    NbAuthModule.forRoot({
      strategies: [
        NbOAuth2AuthStrategy.setup({
          name: 'cognito'
        })
      ],
      ...
    })
  ],
  ...
})
export class AppModule {
  constructor(
    authService: NbAuthService, // force construction of the auth service
    oauthStrategy: NbOAuth2AuthStrategy
  ) {
    // window.location should be available here
    this.oauthStrategy.setOpitions({
      name: 'cognito',
      ...
    });
  }
}

正如我发现的那样,将 . 添加NbAuthService到构造函数参数以及NbOAuth2AuthStrategy. 看起来服务在构建时就初始化了策略,所以应该在策略初始化之前构建。

另请注意,该setOptions()方法完全覆盖了模块装饰器中的选项,因此整个策略初始化应从装饰器移至构造器。

我还发现了这个GitHub 问题,它帮助我找到了正确的解决方案。

于 2019-09-04T08:35:53.397 回答
0

您的解决方案将不起作用,因为正如 Valeriy Katkov 所提到的,在创建类的任何实例之前,类级别的装饰器已应用于构造函数。因此,您将无法将路由器注入装饰器。

为了能够注入路由器,您需要在类中移动您的实现。通过实例的setOptions方法是可能的NbAuthStrategy,但是,有一些问题,例如看这里这里需要克服。为了使其工作,您应该将策略配置移动到扩展NbAuthComponent(这很重要)的组件,例如:

export class AppComponent extends NbAuthComponent {

  constructor(auth: NbAuthService,
              location: Location,
              private router: Router,
              authStrategy: NbPasswordAuthStrategy) {
    super(auth, location);

    authStrategy.setOptions({
      name: 'username',
      login: {
        alwaysFail: false,
        endpoint: 'test',
        method: 'post',
        requireValidToken: false,
        redirect: {
          success: this.router.url + '/success-callback',
          failure: this.location.path() + '/callback'
        },
        defaultErrors: ['Damn'],
        defaultMessages: ['Great'],
      },
    });
  }
}

另外我建议您使用this.location.path(),而不是this.router.url因为this.router.url它不会为您提供您所在的 url,而是组件级别的 url。this.location.path()将为您提供您所在页面的完整路径。

这是一个带有有效解决方案的StackBlitz 示例

请让我知道您是否仍不清楚或需要一些额外的细节。

于 2019-09-05T22:41:47.867 回答
0

如果您想做类似的事情,您可以使用注入令牌并创建一个返回您想要的值的工厂函数。它将在浏览器中运行,您将看到所需的值。

const REDIRECT_URI = new InjectionToken('REDIRECT_URI');

export function redirectUriFactory {
  return `${location.protocol}/${location.host}/callback`
}
    @NgModule(...)
    class MyModule {
      forRoot() {
        return {
          ngModule: MyModule,
          providers: [
            { provide: REDIRECT_URI, useFactory: redirectUriFactory }
          ]
        }
      }
    }

我没有对此进行测试,但是使用 Factory 的 InjectionToken 是 AOT 的必经之路

更多信息https://github.com/angular/angular-cli/issues/10957

于 2019-09-04T08:44:52.337 回答
0

在您提供的代码示例中,您似乎试图在实例化类“”之前访问注释this.router中的路由器对象。@NgModuleAppModule

实例变量在注释中不可用。Angular 使用 [依赖注入][1] 通过构造函数提供对象实例。

看看你的情况,虽然我不太了解模块,但你可以在注释部分NbOAuth2AuthStrategy定义模块后,从构造函数中寻找配置身份验证策略的选项。考虑这个代码片段,它可能对你有帮助。在下面标记的代码中查找占位符import@NgModule<< >>


    NbAuthModule.forRoot({
        forms: {},
      strategies: [
        NbOAuth2AuthStrategy.setup({
          baseEndpoint: environment.authUrl,
          name: 'cognito',
          clientId: environment.clientId,
          authorize: {
            endpoint: '/oauth2/authorize',
            responseType: NbOAuth2ResponseType.CODE,
            scope: 'aws.cognito.signin.user.admin',
            redirectUri: '<<SET SOME DEFAULT URL>>',
          },
          redirect: {
            success: '/pages/dashboard',
          },
          token: {
            endpoint: '/oauth2/token',
            grantType: NbOAuth2GrantType.AUTHORIZATION_CODE,
            class: NbAuthOAuth2Token,
            redirectUri: '<<SET SOME DEFAULT URL>>',
          },
          refresh: {
            endpoint: 'refresh-token',
            grantType: NbOAuth2GrantType.REFRESH_TOKEN,
          },
        }),
       ...


    export class AppModule {
      constructor(private router: Router) {
        <<Reconfigure your NbOAuth2AuthStrategy>>
        NbOAuth2AuthStrategy.setup....
      }
    }


Hope the solution works for you.



  [1]: https://angular.io/guide/dependency-injection
于 2019-09-04T08:57:43.000 回答