我正在设置蓝色/绿色部署,并尝试根据用户正在查看的当前URL(redirectUri
)更改下面的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'
,它在本地工作,但是在为生产而构建时为null。
答案 0 :(得分:2)
请注意,在创建类的任何实例之前,将class level decorators应用于构造函数。因此,路由器属性不适用于装饰器。在示例this.router.url + '/callback'
引用全局this
的情况下,很奇怪没有编译错误。
关于window.location
,在aot
编译模式下(默认为prod构建),装饰器中的表达式由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()
方法完全覆盖了模块装饰器中的选项,因此,整个策略初始化应从装饰器移至构造器。
我还发现了this的GitHub问题,这有助于我找到正确的解决方案。
答案 1 :(得分: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的必经之路
答案 2 :(得分:0)
在您提供的代码示例中,您似乎在实例化类“ this.router
”之前尝试访问@NgModule
批注中的路由器对象AppModule
。
实例变量在注释中不可用。 Angular使用[Dependency Injection] [1]通过构造函数提供对象实例。
根据您的情况,虽然我不太了解NbOAuth2AuthStrategy
模块,但是在定义了import
部分的模块后,您可以在构造函数中寻找配置auth策略的选项@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
答案 3 :(得分:0)
您的解决方案将不起作用,因为正如Valeriy Katkov提到的那样,在创建类的任何实例之前,将类级别的装饰器应用于构造函数。因此,您将无法将路由器注入到装饰器中。
为了能够注入路由器,您需要在类内部移动实现。可以通过setOptions
实例的NbAuthStrategy
方法来实现,但是存在一些问题,例如需要解决的问题here或here。
为了使它起作用,您应该将策略配置移至扩展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,而是为您提供Compoment级别的URL。 this.location.path()
将为您提供所在页面的完整路径。
这是一个StackBlitz example,具有有效的解决方案。
请让我知道您是否仍然不清楚或需要进一步详细说明。