角度4:可观察不起作用

时间:2017-12-19 10:23:28

标签: angular observable

我正在使用的应用程序通过Angular 2+的adal.js端口实现Azure Active Directory授权,该端口运行良好。

我们有一个AuthenticationGuard来处理来自我们AdalService的呼叫。 AdalService有一个函数ensureAuthenticatedAsync,用于检查用户是否已登录,如果没有,则将其重定向到AD登录页面。

我们现在有了新的要求,即在没有AD帐户可用时,可以使用自定义生成的令牌替代登录。经过一些修改后,我的代码如下所示:

authentication.guard.ts

public canActivate(route: ActivatedRouteSnapshot, state RouterStateSnapshot) : boolean {
    ...
    let params = route.queryParams;
    let token = (params !== null && params['token'] !== undefined) ? params['token'] : null;

    this.adalService.ensureAuthenticatedAsync(token);
    ...
    return true;
}

adal.service.ts

private context: adal.AuthenticationContext;

public ensureAuthenticatedAsync(token: string | null = null) {
    console.log('ensureAuthenticatedAsync', token);
    this.isAuthenticated.subscribe(isAuthenticated => {
        if (!isAuthenticated) {
            console.log('not authenticated);
            if (token === null) {
                // forward to AAD login page -> this works perfectly
                this.context.login();
            } else {
                ...
                console.log('accessToken before', this.accessToken);
                this.customToken = token;
                console.log('accessToken after', this.accessToken);
                ...
            }
        }
    });
}

public get accessToken(): string {
    console.log('customToken in get accessToken', this.customToken);
    return (this.customToken === null) ? this.context.getCachedToken(this.adalClientId) : this.customToken;
}

public get isAuthenticated(): Observable<boolean> {
    console.log('accessToken in get isAuthenticated', this.accessToken);
    let isAuthenticated: boolean = (this.accessToken !== null);
    return Observable.of(isAuthenticated);
}

app.component.ts

public ngOnInit(): void {
    this.adalService.isAuthenticated.subscribe(isAuthenticated => {
        if (isAuthenticated) {
            // do some stuff here
        }
    });
}

app.routes.ts

export const ROUTES: Routes = [
    { path: 'Dashboard', component: DashboardComponent, canActivate: [AuthenticationGuard] },
    { path: 'Access-Denied', component: AccessDeniedComponent }
];

这是在控制台中记录的内容:

authentication guard  
customToken in get accessToken null  
accessToken in get isAuthenticated null  
customToken in get accessToken null  
ensureAuthenticatedAsync 12345  
not authenticated  
customToken in get accessToken null  
accessToken before null  
customToken in get accessToken 12345  
accessToken after 12345  
customToken in get accessToken 12345

定期访问该页面(http://localhost:3000/Dashboard)会正确触发重定向到AD登录页面,然后在登录后返回到我的应用程序。在那里,缓存的AD令牌被更改,并且在任何订阅的地方都会触发isAuthenticated(在我的情况下在app.component.ts中)。

但是,使用令牌(http://localhost:3000/Dashboard/?token=12345)访问页面不起作用。尽管使用参数中的值修改了customToken,但似乎没有传播更改,并且isAuthenticated在订阅中保留false

我错过了什么吗?

2 个答案:

答案 0 :(得分:2)

我认为问题在于警卫本地化。

你的警卫在/仪表板路线上。因此,如果仅加载http://localhost:3000/?token=12345,则不会调用AuthenticationGuard,因此也不会调用ensureAuthenticatedAsync。因此,您没有重定向,也没有在adal.service.ts中更新customToken。

如果你想在appComponent中使用你守卫的计算结果,你必须使用路线上的守卫&#34;领先&#34;到appComponent

编辑: 问题是你误解了反应行为。方法isAuthenticated实现它会发出一次布尔值然后完成。因此,您在app.component中的订阅只会触发一次。

您正在寻找的是行为主体,您可以在哪里推动&#34;需要时或者customToken更改时的新数据。

答案 1 :(得分:1)

尝试:

在您的 adal.service.ts

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
...
public get isAuthenticated(): Observable<boolean> {
 let isAuthenticated: boolean = (this.accessToken !== null);
 return of(isAuthenticated);
}