从路由器加载 URL 以在 NgModule 中使用



我正在设置蓝/绿部署,并尝试根据用户正在查看的当前网址(redirectUri: this.router.url + '/callback',(更改下面的redirectUri。我收到具有以下配置的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',但在为生产而构建时为空。

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

关于window.location,在aot编译模式下(这是生产构建的默认模式(,装饰器中的表达式由 Angular 编译器在编译时执行,因此window.location在那里不可用。看看这个 GitHub 问题:AOT 将 window.location 对象替换为空

作为一种解决方法,您可以动态初始化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 问题,这有助于我找到正确的解决方案。

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

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 }
]
}
}
}

我没有对此进行测试,但是当它来到AOT时,带有工厂的InjectionToken是要走的路。

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

在您提供的代码示例中,您似乎正在尝试在实例化类"AppModule"之前访问this.router@NgModule注释中的路由器对象。

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

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


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

您的解决方案将不起作用,因为正如 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 示例。

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

相关内容

最新更新